# Get account settings Source: https://docs.straddle.com/api-reference/accounts/account-settings get /v1/account_settings/{account_id} Get all resolved settings for the specified account, including inherited values from organization, platform, and system defaults. # Create an account Source: https://docs.straddle.com/api-reference/accounts/create post /v1/accounts Creates a new account associated with your Straddle platform integration. This endpoint allows you to set up an account with specified details, including business information and access levels. # List accounts Source: https://docs.straddle.com/api-reference/accounts/list get /v1/accounts Returns a list of accounts associated with your Straddle platform integration. The accounts are returned sorted by creation date, with the most recently created accounts appearing first. This endpoint supports advanced sorting and filtering options. # Lookup an account Source: https://docs.straddle.com/api-reference/accounts/lookup get /v1/accounts/{account_id} Retrieves the details of an account that has previously been created. Supply the unique account ID that was returned from your previous request, and Straddle will return the corresponding account information. # Onboard an account Source: https://docs.straddle.com/api-reference/accounts/onboard post /v1/accounts/{account_id}/onboard Initiates the onboarding process for a new account. This endpoint can only be used for accounts where at least one representative and one bank account have already been created. Prior to onboarding via this endpoint you must capture consent to the Straddle Payment Services Agreement ([legal.straddle.com](https://legal.straddle.com)). # Simulate account onboarding in sandbox Source: https://docs.straddle.com/api-reference/accounts/simulate post /v1/accounts/{account_id}/simulate Simulate the status transitions for sandbox accounts. This endpoint can only be used for sandbox accounts. # Update an account Source: https://docs.straddle.com/api-reference/accounts/update put /v1/accounts/{account_id} Updates an existing account's information. This endpoint allows you to update various account details during onboarding or after the account has been created. # API authentication with bearer tokens Source: https://docs.straddle.com/api-reference/authentication Authenticate Straddle API requests using JWT bearer tokens. Generate API keys, manage sandbox and production credentials, and follow security best practices. Securing your API requests is crucial when integrating with Straddle. This guide walks you through the authentication process, ensuring your API calls are properly authenticated and your data remains secure. ## Overview Straddle uses Bearer Token authentication via JSON Web Tokens (JWT) for all API requests. Each request must include a valid API key in the `Authorization` header as a Bearer token. All API requests must be made over HTTPS. Calls made over plain HTTP will fail. ## Obtaining your API key Before you can authenticate your requests, you'll need to obtain an API key from the Straddle Dashboard: 1. Log in to your [Straddle Dashboard](https://dashboard.straddle.com). 2. Select the **Developer** (``) icon in the top-right corner of the navigation bar. 3. Select **API Keys** from the dropdown menu. 4. Select **Generate New API Key**. 5. Copy your new API key and store it securely. Your API key carries many privileges, so be sure to keep it secure! Do not share your API keys in publicly accessible areas such as GitHub, client-side code, or in your application logs. ## Using your API key To authenticate an API request, include your API key in the `Authorization` header. The value should be formatted as `Bearer YOUR_API_KEY`. Here's an example of how to include the `Authorization` header in your API requests: ```bash cURL theme={null} curl https://sandbox.straddle.com/v1/accounts \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJvcmdfMmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iiwib3JnIjoiYWNtZS1jb3JwIiwiZW52Ijoic2FuZGJveCIsImlhdCI6MTcxMTU1OTAwMCwiZXhwIjoxNzExNjQ1NDAwfQ.VGhpcyBpcyBhIHNpbXVsYXRlZCBSUzI1NiBzaWduYXR1cmUgZm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXMgb25seQ" \ -H "Content-Type: application/json" ``` ```javascript Node.js theme={null} const apiKey = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJvcmdfMmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iiwib3JnIjoiYWNtZS1jb3JwIiwiZW52Ijoic2FuZGJveCIsImlhdCI6MTcxMTU1OTAwMCwiZXhwIjoxNzExNjQ1NDAwfQ.VGhpcyBpcyBhIHNpbXVsYXRlZCBSUzI1NiBzaWduYXR1cmUgZm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXMgb25seQ' async function listAccounts() { const res = await fetch('https://sandbox.straddle.com/v1/accounts', { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }) const json = await res.json() console.log(json) } listAccounts().catch(err => console.error('Error:', err)) ``` ```python Python theme={null} import requests api_key = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJvcmdfMmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iiwib3JnIjoiYWNtZS1jb3JwIiwiZW52Ijoic2FuZGJveCIsImlhdCI6MTcxMTU1OTAwMCwiZXhwIjoxNzExNjQ1NDAwfQ.VGhpcyBpcyBhIHNpbXVsYXRlZCBSUzI1NiBzaWduYXR1cmUgZm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXMgb25seQ' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } response = requests.get('https://sandbox.straddle.com/v1/accounts', headers=headers) print(response.json()) ``` ## API environments Straddle provides two public environments, each with its own base URL and API keys: | Environment | Base URL | Purpose | | - | - | - | | **Sandbox** | `https://sandbox.straddle.com` | Testing and development — no real financial transactions are processed | | **Production** | `https://production.straddle.com` | Live transactions with real customer data and banking networks | API keys are environment-specific. A sandbox API key doesn't authenticate against the production environment, and vice versa. Always verify you are using the correct key for your target environment. Always use sandbox API keys when developing and testing your integration. Only switch to production keys when you're ready to go live. ## Required headers In addition to the `Authorization` header, Straddle recommends including the following headers with your requests: | Header | Required | Description | | - | - | - | | `Content-Type` | Yes | Set to `application/json` for request bodies | | `Request-Id` | No | A unique identifier useful for tracking and debugging individual API requests | | `Correlation-Id` | No | Used to group related requests within larger operations or transactions for easier debugging | While `Request-Id` and `Correlation-Id` are optional, we strongly recommend including them. They make it much easier to trace and debug API requests when troubleshooting issues. ## Best practices To ensure the security of your integration, follow these best practices: 1. **Keep your API key secret**: Never expose your API key in client-side code or public repositories. 2. **Use environment variables**: Store your API key in environment variables rather than hardcoding it in your application. 3. **Rotate your API keys**: Regularly generate new API keys and update your applications to use them. 4. **Monitor API key usage**: Regularly review your API key usage in the Straddle Dashboard to detect any unauthorized access. 5. **Match keys to environments**: Always confirm your API key matches the environment you're targeting before processing requests. ## Handling authentication errors If your API key is invalid, expired, or has been revoked, you'll receive a `401 Unauthorized` response: ```json theme={null} { "error": { "code": "invalid_api_key", "message": "The provided API key is invalid or has been revoked.", "type": "authentication_error" } } ``` If you encounter this error, verify the following: 1. Confirm you're using the correct API key. 2. Check whether your key has been revoked or expired. 3. Ensure you're targeting the correct environment (sandbox or production) for the key you're using. ## Next steps Now that you understand how to authenticate your API requests, you're ready to start integrating with Straddle. Check out our [API Reference](/api-reference) for detailed information on available endpoints and how to use them. # Bridge a bank account Source: https://docs.straddle.com/api-reference/bridge/bank-account post /v1/bridge/bank_account Use Bridge to create a new paykey using a bank routing and account number as the source. This endpoint allows you to create a secure payment token linked to a specific bank account. # Bridge a Mastercard consent receipt Source: https://docs.straddle.com/api-reference/bridge/mastercard post /v1/bridge/mastercard Creates a new paykey from a Mastercard Open Finance connection your application already owns. Supply the consent receipt granting Straddle third-party access along with the pseudonymous Mastercard customer and account identifiers, and Straddle retrieves the bank details, account holder names, and live balance on your behalf. # Bridge a Plaid token Source: https://docs.straddle.com/api-reference/bridge/plaid-token post /v1/bridge/plaid Use Bridge to create a new paykey using a Plaid token as the source. This endpoint allows you to create a secure payment token linked to a bank account authenticated through Plaid. # Bridge a Quiltt token Source: https://docs.straddle.com/api-reference/bridge/quiltt-token post /v1/bridge/quiltt Creates a new paykey using a Quiltt token as the source. This endpoint allows you to create a secure payment token linked to a bank account authenticated through Quiltt. # Initiate a widget session Source: https://docs.straddle.com/api-reference/bridge/session post /v1/bridge/initialize Use this endpoint to generate a session token for use in the Bridge widget. # Request a capability Source: https://docs.straddle.com/api-reference/capabilityrequests/create post /v1/accounts/{account_id}/capability_requests Submits a request to enable a specific capability for an account. Use this endpoint to request additional features or services for an account. # List capability requests Source: https://docs.straddle.com/api-reference/capabilityrequests/list get /v1/accounts/{account_id}/capability_requests Retrieves a list of capability requests associated with an account. The requests are returned sorted by creation date, with the most recent requests appearing first. This endpoint supports advanced sorting and filtering options. # Upload proof of authorization for a charge Source: https://docs.straddle.com/api-reference/charges/authorize post /v1/charges/{id}/authorization Uploads a document as proof of authorization for a charge. Uploading again adds another entry to documents rather than replacing the previous one. # Cancel a charge Source: https://docs.straddle.com/api-reference/charges/cancel put /v1/charges/{id}/cancel Cancel a charge to prevent it from being originated for processing. The status of the charge must be `created`, `scheduled`, or `on_hold`. # Create a charge Source: https://docs.straddle.com/api-reference/charges/create post /v1/charges Use charges to collect money from a customer for the sale of goods or services. In ACH terminology, Straddle charges are **ACH debit transactions** that pull money from customer bank accounts. Learn more about [ACH debits](/help/ACH101/ach-debit) and [authorization requirements](/help/Payment-Compliance/ach-auth) to ensure compliant payment collection. # Hold a charge Source: https://docs.straddle.com/api-reference/charges/hold put /v1/charges/{id}/hold Place a charge on hold to prevent it from being originated for processing. The status of the charge must be `created` or `scheduled`. # Refund a charge Source: https://docs.straddle.com/api-reference/charges/refund post /v1/charges/{id}/refund Issue a refund for a successfully paid charge. The refund is created as a new payout linked to the original charge through `related_payments`. The customer receives the funds back at the bank account they paid from. Each charge can be refunded once; partial and full refunds are both supported. # Release a charge Source: https://docs.straddle.com/api-reference/charges/release put /v1/charges/{id}/release Release a charge from an `on_hold` status to allow it to be rescheduled for processing. # Resubmit a charge Source: https://docs.straddle.com/api-reference/charges/resubmit post /v1/charges/{id}/resubmit Recover a failed, reversed, or cancelled ACH debit by creating a new charge linked to the original transaction and retaining payment history. # Lookup a charge Source: https://docs.straddle.com/api-reference/charges/retrieve get /v1/charges/{id} Retrieves the details of an existing charge. Supply the unique charge `id`, and Straddle will return the corresponding charge information. # Update a charge Source: https://docs.straddle.com/api-reference/charges/update put /v1/charges/{id} Change the values of parameters associated with a charge prior to processing. The status of the charge must be `created`, `scheduled`, or `on_hold`. # Create a customer Source: https://docs.straddle.com/api-reference/customers/create post /v1/customers Creates a new customer record and automatically initiates identity, fraud, and risk assessment scores. This endpoint allows you to create a customer profile and associate it with paykeys and payments. # Decision a customer Source: https://docs.straddle.com/api-reference/customers/decision patch /v1/customers/{id}/review Updates the status of a customer's identity decision. This endpoint allows you to modify the outcome of a customer risk screening and is useful for correcting or updating the status of a customer's verification. Note that this endpoint is only available for customers with a current status of `review`. # Delete a customer Source: https://docs.straddle.com/api-reference/customers/delete delete /v1/customers/{id} Permanently removes a customer record from Straddle. This action cannot be undone and should only be used to satisfy regulatory requirements or for privacy compliance. # Lookup a customer Source: https://docs.straddle.com/api-reference/customers/retrieve get /v1/customers/{id} Retrieves the details of an existing customer. Supply the unique customer ID that was returned from your 'create customer' request, and Straddle will return the corresponding customer information. # Review a customer Source: https://docs.straddle.com/api-reference/customers/review get /v1/customers/{id}/review Retrieves and analyzes the results of a customer's identity validation and fraud score. This endpoint provides a comprehensive breakdown of the validation outcome, including: - Risk and correlation scores - Reason codes for the decision - Results of watchlist screening - Any network alerts detected Use this endpoint to gain insights into the verification process and make informed decisions about customer onboarding. # List customers Source: https://docs.straddle.com/api-reference/customers/search get /v1/customers Lists or searches customers connected to your account. All supported query parameters are optional. If none are provided, the response will include all customers connected to your account. This endpoint supports advanced sorting and filtering options. # Unmask customer data Source: https://docs.straddle.com/api-reference/customers/unmask get /v1/customers/{id}/unmasked Retrieves the unmasked details, including PII, of an existing customer. Supply the unique customer ID that was returned from your 'create customer' request, and Straddle will return the corresponding customer information. This endpoint needs to be enabled by Straddle and should only be used when absolutely necessary. This endpoint is not enabled by default.

Please contact [compliance@straddle.com](mailto:compliance@straddle.com) to request access.
# Update a customer Source: https://docs.straddle.com/api-reference/customers/update put /v1/customers/{id} Updates an existing customer's information. This endpoint allows you to modify the customer's contact details, PII, and metadata. Updating more than two fields (not including `metadata`) within a 24 hour period will trigger a new [identity](/guides/identity/overview) score. # Make API calls for embedded accounts Source: https://docs.straddle.com/api-reference/embedded-accounts Use the Straddle-Account-Id header to make API requests on behalf of your embedded accounts, including charges, payouts, and customer operations. For platforms building on Embed, you can make API calls on behalf of your embedded accounts. This guide walks you through the process of adding the necessary information to your API calls to act on behalf of your connected accounts. ## Overview You can make API calls for your embedded accounts in two ways: 1. Server-side using the `Straddle-Account-Id` header and the embedded account ID, per request 2. Client-side by passing the embedded account ID as an argument to the client library To ensure optimal performance and reliability, Straddle has established rate limits and allocations for API endpoints. These limits apply collectively to all requests made on behalf of embedded accounts. ## Server-side requests: Using the Straddle-Account-Id header For server-side API calls, you can make requests as embedded accounts using the special header `Straddle-Account-Id` with the Straddle account identifier (prefixed with `acct_`) of your platform user. ### Example: Creating a charge Here's an example that shows how to create a Charge with your platform's API secret key and your user's Account identifier: ```bash cURL theme={null} curl https://sandbox.straddle.com/v1/charges \ -H "Authorization: Bearer 51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" \ -H "Straddle-Account-Id: 1234567890" \ -d amount=1000 \ -d currency=usd \ -d paykey="pk_test_TYooMQauvdEDq54NiTphI7jx" ``` ```javascript Node.js theme={null} const Straddle = require('straddle'); const straddle = new Straddle('51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); straddle.charges.create({ amount: 1000, currency: 'usd', paykey: 'pk_test_TYooMQauvdEDq54NiTphI7jx' }, { straddleAccountId: 'acct_1234567890' }).then(charge => { console.log(charge); }).catch(error => { console.error(error); }); ``` ```python Python theme={null} import straddle straddle.api_key = "51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" charge = straddle.Charge.create( amount=1000, currency="usd", paykey="pk_test_TYooMQauvdEDq54NiTphI7jx", straddle_account_id="acct_1234567890" ) print(charge) ``` ## Client-side requests For client-side API calls, you can pass the embedded account ID as an argument when initializing the Straddle client. Here's an example: *COMING SOON* Be cautious when using client-side requests for embedded accounts. Ensure that you're not exposing sensitive information or granting unnecessary permissions to the client. ## Best practices When making API requests for embedded accounts, keep these best practices in mind: 1. **Use server-side requests when possible**: This gives you more control over the API calls and keeps sensitive information secure. 2. **Validate the embedded account ID**: Before making a request on behalf of an embedded account, ensure that the account ID is valid and belongs to your platform. 3. **Handle errors gracefully**: Be prepared to handle errors that may occur when making requests for embedded accounts, such as account not found or insufficient permissions. 4. **Monitor API usage**: Keep track of the API calls made on behalf of your embedded accounts to ensure you're within rate limits and to detect any unusual activity. 5. **Use webhooks**: Set up webhooks to receive real-time notifications about events related to your embedded accounts. ## Rate limits Straddle applies rate limits to API requests to ensure fair usage and system stability. These limits apply collectively to all requests made by your platform, including those made on behalf of embedded accounts. If you need higher rate limits for your platform, contact Straddle support to discuss your requirements. ## Conclusion Making API requests on behalf of embedded accounts is a powerful feature that allows you to build sophisticated platforms on top of Straddle. Follow the guidelines in this document to make these requests correctly and securely. For more information on specific API endpoints and how they behave when used with embedded accounts, refer to our [API Reference](/api-reference) documentation. # Sandbox and production environments Source: https://docs.straddle.com/api-reference/environments Compare Straddle's sandbox and production API environments, including base URLs, credentials, testing workflows, and how to safely promote integrations to live. Straddle provides two distinct environments for developers: a sandbox environment for testing and a production environment for live transactions. This guide helps you understand the differences between these environments and how to use them effectively in your development process. ## Overview Straddle offers two environments: 1. **Sandbox Environment**: `https://sandbox.straddle.com` 2. **Production Environment**: `https://production.straddle.com` Each environment serves a specific purpose in your development lifecycle. ## Sandbox environment The sandbox environment (`https://sandbox.straddle.com`) is designed for testing and development purposes. It allows you to integrate and experiment with Straddle's API without affecting real data or triggering actual financial transactions. ### Key features of the sandbox environment * Simulates the behavior of the production environment * Uses sandbox API keys * Does not process real financial transactions * Provides pre-defined test data and scenarios * No rate limits or usage restrictions ### When to use the sandbox environment Use the sandbox environment when: * Developing and testing your integration * Experimenting with new features * Running automated tests * Demonstrating your application without using real data ### Accessing the sandbox environment To use the sandbox environment, make API requests to `https://sandbox.straddle.com` and use your test API key for authentication. Example API request to the sandbox environment: ```bash cURL theme={null} curl https://sandbox.straddle.com/v1/accounts \ -H "Authorization: Bearer 71aVYucgQ8o0ymsuaT0ymEEQUR03NrYAqoy58Z53n9LHgRmJlMp8HSbOOBl6TWi" ``` ```javascript Node.js theme={null} const apiKey = '71aVYucgQ8o0ymsuaT0ymEEQUR03NrYAqoy58Z53n9LHgRmJlMp8HSbOOBl6TWi' async function listAccounts() { const res = await fetch('https://sandbox.straddle.com/v1/accounts', { headers: { 'Authorization': `Bearer ${apiKey}` } }) const json = await res.json() console.log(json) } listAccounts().catch(err => console.error('Error:', err)) ``` ```python Python theme={null} import requests api_key = '71aVYucgQ8o0ymsuaT0ymEEQUR03NrYAqoy58Z53n9LHgRmJlMp8HSbOOBl6TWi' headers = { 'Authorization': f'Bearer {api_key}' } response = requests.get('https://sandbox.straddle.com/v1/accounts', headers=headers) print(response.json()) ``` ## Production environment The production environment (`https://production.straddle.com`) is used for live, real-world transactions. This is where your application interacts with actual customer data and process real financial transactions. ### Key features of the production environment * Processes real financial transactions * Uses live API keys * Interacts with real customer data * Subject to rate limits and usage restrictions * Monitored for performance and reliability ### When to use the production environment Use the production environment when: * Your application is ready for real-world use * Processing actual financial transactions * Working with real customer data ### Accessing the production environment To use the production environment, make API requests to `https://production.straddle.com` and use your live API key for authentication. Example API request to the production environment: ```bash cURL theme={null} curl https://production.straddle.com/v1/accounts \ -H "Authorization: Bearer 51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" ``` ```javascript Node.js theme={null} const apiKey = '51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1' async function listAccountsProd() { const res = await fetch('https://production.straddle.com/v1/accounts', { headers: { 'Authorization': `Bearer ${apiKey}` } }) const json = await res.json() console.log(json) } listAccountsProd() ``` ```python Python theme={null} import requests api_key = '51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1' headers = { 'Authorization': f'Bearer {api_key}' } response = requests.get('https://production.straddle.com/v1/accounts', headers=headers) print(response.json()) ``` ## Best practices To ensure a smooth transition from development to production, follow these best practices: 1. **Use environment variables**: Store your API keys and environment URLs as environment variables to easily switch between sandbox and production. 2. **Thoroughly test in sandbox**: Extensively test your integration in the sandbox environment before moving to production. 3. **Gradual rollout**: When moving to production, consider a phased rollout to minimize potential issues. 4. **Monitor closely**: Keep a close eye on your production transactions and be prepared to switch back to sandbox if issues arise. 5. **Keep environments separate**: Never mix sandbox and production data or API keys. ## Transitioning from sandbox to production When you're ready to go live with your Straddle integration, follow these steps: 1. Review and test all features in the sandbox environment. 2. Update your API key to the live production key. 3. Change your API endpoint from `https://sandbox.straddle.com` to `https://production.straddle.com`. 4. Update any environment-specific configurations or settings. 5. Perform final testing in production with real data (start with small, controlled transactions). 6. Monitor your production transactions closely for any issues. Always double-check that you're using the correct environment and API key before processing real transactions. Using sandbox credentials in production can lead to failed transactions and poor user experience. ## Conclusion Understanding and properly utilizing Straddle's sandbox and production environments is crucial for successful integration and deployment. Follow the guidelines and best practices in this guide to ensure a smooth development process and transition to production. For more detailed information on specific API endpoints and how they behave in different environments, refer to our [API Reference](/api-reference) documentation. # API errors and HTTP status codes Source: https://docs.straddle.com/api-reference/errors Learn how to interpret HTTP status codes and error responses from the Straddle API, including validation, authentication, and rate limit errors. When working with the Straddle API, it's crucial to properly handle HTTP errors to ensure your application can gracefully manage unexpected situations. This guide walks you through the different types of errors you might encounter, how to interpret them, and best practices for error handling. ## Common HTTP errors Here's a quick reference table of common HTTP errors you might encounter when using the Straddle API:
Status Code Error Type Description Common Causes
400 Bad Request The request was unacceptable, often due to missing a required parameter.
  • Missing required fields
  • Invalid field values
  • Malformed JSON
401 Unauthorized No valid API key provided.
  • Invalid API key
  • Expired API key
403 Forbidden The API key doesn't have permissions to perform the request.
  • Insufficient permissions
  • Incorrect account access
404 Not Found The requested resource doesn't exist.
  • Incorrect resource ID
  • Deleted resource
422 Unprocessable Entity The request was well-formed but was unable to be followed due to semantic errors.
  • Invalid parameter values
  • Logical errors in request
429 Too Many Requests Too many requests hit the API too quickly.
  • Exceeding rate limits
500 Internal Server Error Something went wrong on Straddle's end.
  • Unexpected server issues
## Understanding HTTP status codes Straddle uses standard HTTP status codes to indicate the success or failure of an API request. Here are the main categories: * 2xx: Success * 4xx: Client errors * 5xx: Server errors ## Common error responses When an error occurs, Straddle returns a JSON object with details about the error. The structure of this object is consistent across all error types: ```json theme={null} { "error": { "code": "error_code", "message": "A human-readable message providing more details about the error.", "type": "error_type" } } ``` ## Types of errors ### 400 Bad Request This error occurs when the request is malformed or contains invalid parameters. Example response: ```json theme={null} { "error": { "code": "invalid_request_error", "message": "The 'amount' parameter is required and must be a positive integer.", "type": "invalid_request_error" } } ``` How to handle: * Check your request parameters for any missing or invalid values. * Ensure all required fields are included and formatted correctly. ### 401 Unauthorized This error occurs when authentication fails, typically due to an invalid API key. Example response: ```json theme={null} { "error": { "code": "invalid_api_key", "message": "The provided API key is invalid or has been revoked.", "type": "authentication_error" } } ``` How to handle: * Verify that you're using the correct API key. * Check if your API key has been revoked or expired. * Ensure you're using the correct environment (test vs. production). ### 403 Forbidden This error occurs when the authenticated user doesn't have permission to perform the requested action. Example response: ```json theme={null} { "error": { "code": "permission_denied", "message": "You don't have permission to access this resource.", "type": "authentication_error" } } ``` How to handle: * Check if the authenticated account has the necessary permissions. * If you're using a platform account, ensure you've correctly specified the `Straddle-Account-Id` header. ### 404 Not Found This error occurs when the requested resource doesn't exist. Example response: ```json theme={null} { "error": { "code": "resource_missing", "message": "The requested resource does not exist.", "type": "invalid_request_error" } } ``` How to handle: * Verify that you're using the correct resource ID. * Check if the resource has been deleted or hasn't been created yet. ### 422 Unprocessable Entity This error occurs when the request is well-formed, but contains invalid data. Example response: ```json theme={null} { "error": { "code": "invalid_parameter", "message": "The 'amount' parameter must be greater than 0.", "type": "invalid_request_error" } } ``` How to handle: * Review the error message for specific details about which parameter is invalid. * Adjust your request data accordingly. ### 429 Too Many Requests This error occurs when you've exceeded the rate limit for API requests. Example response: ```json theme={null} { "error": { "code": "rate_limit_exceeded", "message": "You have exceeded the rate limit. Please try again later.", "type": "rate_limit_error" } } ``` How to handle: * Implement exponential backoff and retry logic in your application. * Consider optimizing your code to make fewer API requests. ### 500 Internal Server Error This error indicates an unexpected condition on the server side. Example response: ```json theme={null} { "error": { "code": "internal_server_error", "message": "An unexpected error occurred. Please try again later.", "type": "api_error" } } ``` How to handle: * Implement a retry mechanism with exponential backoff. * If the error persists, contact Straddle support and provide the Request-Id and Correlation-Id. ## Best practices for error handling 1. **Always check the HTTP status code**: Don't assume a request was successful. Always check the HTTP status code before processing the response. 2. **Parse the error response**: Extract the error details from the JSON response to get more information about what went wrong. 3. **Log errors with context**: When logging errors, include relevant context such as the Request-Id, Correlation-Id, and any pertinent request details. 4. **Implement retry logic**: For transient errors (like rate limiting or temporary server issues), implement a retry mechanism with exponential backoff. 5. **Provide meaningful error messages to users**: Translate API errors into user-friendly messages in your application's UI. 6. **Monitor error rates**: Keep track of the frequency and types of errors you're encountering to identify and address recurring issues. ## Example: Error handling in Node.js Here's an example of how you might handle errors when making a request to the Straddle API: ```javascript theme={null} const Straddle = require('straddle') const straddle = new Straddle('sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1') async function createCharge(amount, currency, paykey) { try { const charge = await straddle.charges.create({ amount, currency, paykey, payment_date: new Date().toISOString().split('T')[0], consent_type: 'internet' }) return charge } catch (error) { if (error.statusCode === 400) { console.error('Invalid request:', error.message) } else if (error.statusCode === 401) { console.error('Authentication failed:', error.message) } else if (error.statusCode === 429) { console.error('Rate limit exceeded. Retrying in 5 seconds...') await new Promise(resolve => setTimeout(resolve, 5000)) return createCharge(amount, currency, paykey) } else { console.error('An unexpected error occurred:', error.message) } throw error } } createCharge(1000, 'usd', 'pk_test_TYooMQauvdEDq54NiTphI7jx') .then(charge => console.log('Charge created:', charge.id)) .catch(error => console.error('Failed to create charge:', error)) ``` This example demonstrates how to catch and handle different types of errors, including implementing a simple retry mechanism for rate limiting errors. ## Conclusion Proper error handling is crucial for building robust applications that integrate with the Straddle API. Understand the different types of errors, implement appropriate error handling strategies, and follow best practices. This helps you create a smoother experience for your users and more easily diagnose and resolve issues when they arise. Remember to always refer to the [API Reference](/api-reference) documentation for the most up-to-date information on error codes and handling for specific endpoints. # Lookup funding details Source: https://docs.straddle.com/api-reference/funding/details get /v1/funding_events/{id} Retrieves the details of an existing funding event. Supply the unique funding event `id`, and Straddle will return the individual transaction items that make up the funding event. # List funding events Source: https://docs.straddle.com/api-reference/funding/search get /v1/funding_events Retrieves a list of funding events for your account. This endpoint supports advanced sorting and filtering options. # Simulate a funding event in sandbox Source: https://docs.straddle.com/api-reference/funding/simulate POST /v1/funding_events/simulate Simulate a funding event for testing. This endpoint can only be used in the sandbox environment. # Idempotency keys for safe API retries Source: https://docs.straddle.com/api-reference/idempotency Use the Idempotency-Key header to safely retry Straddle API requests without duplicating operations like charges or payouts. Includes best practices. Straddle supports idempotent API requests, which means you can safely retry requests without fear of performing the same operation multiple times. This is especially important for operations that change state, like creating a payment, where duplicate requests could lead to financial discrepancies. ## Overview Idempotency is achieved by including a unique `Idempotency-Key` header in your HTTP requests. Straddle then uses this key to detect and prevent duplicate operations. If a request with a given key has already been processed, Straddle returns the original response without re-executing the operation. Idempotency is currently supported for **POST** and **PATCH** requests only and requires API key authentication. ## How it works When you send a request with an `Idempotency-Key` header: 1. Straddle checks if a request with that key has been seen before. 2. If it's a new key, the request is processed normally. The key and the request's details (path, method, body hash) are stored. 3. If the key has been seen before: * If the previous request with that key is still in progress, a `409 Conflict` error is returned, indicating a concurrent request. * If the previous request completed and the requests are identical, the original response is replayed with an `Idempotent-Replayed: true` header. * If the idempotency key is reused for a non-identical request, a `409 Conflict` error is returned, indicating that the key has been reused for a different request. 4. Idempotency keys are only stored for a limited period of time (\~24 hours). ## Using your idempotency key To make an idempotent API request, include a unique string in the `Idempotency-Key` header. We require a key length of 10-40 characters. Here's an example of how to include the `Idempotency-Key` header in your API requests: ```bash cURL theme={null} curl -X POST https://sandbox.straddle.com/v1/charges \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: unique-client-key-7890" \ -d '{ "amount": 100.00, "currency": "USD", }' ``` ```javascript Node.js theme={null} const apiKey = 'YOUR_API_KEY' const idempotencyKey = 'unique-client-key-7890' async function createCharge() { const res = await fetch('https://sandbox.straddle.com/v1/charges', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey }, body: JSON.stringify({ amount: 100.00, currency: 'USD' }) }) const json = await res.json() console.log(json) } createCharge().catch(err => console.error('Error:', err)) ``` ```python Python theme={null} import requests api_key = 'YOUR_API_KEY' idempotency_key = 'unique-client-key-7890' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json', 'Idempotency-Key': idempotency_key } payload = { "amount": 100.00, "currency": "USD" } response = requests.post('https://sandbox.straddle.com/v1/charges', headers=headers, json=payload) print(response.json()) ``` ### Response headers (replayed) When an identical request is successfully replayed, the response includes the original HTTP status code, original response headers, and the original response body, with an additional header: ``` HTTP/1.1 201 Created Idempotent-Replayed: true Content-Type: application/json ``` ## Handling idempotency errors Straddle returns specific `409 Conflict` errors in idempotency-related scenarios: ### Idempotency key reused for a different request If you send a request with an `Idempotency-Key` that was previously used for a different request (e.g., different path, method, or request body), you receive a `409 Conflict` error. ```json theme={null} { "status": 409, "type": "/conflict", "title": "Conflict", "detail": "Idempotency key already used for a different request." } ``` **Recommended Action**: Generate a new, unique `Idempotency-Key` for each distinct logical operation. ### Concurrent request in progress If you send a request with an `Idempotency-Key` that is currently being processed by another request, you receive a `409 Conflict` error. ```json theme={null} { "status": 409, "type": "/conflict", "title": "Conflict", "detail": "Previous identical request currently in progress." } ``` **Recommended Action**: Back off and retry the transaction with the same idempotency key. If the retry returns an unsuccessful status, you can safely retry the transaction with a new idempotency key. ### Invalid idempotency key If the `Idempotency-Key` header is supplied and does not meet the length requirements (10-40 characters), Straddle returns a `400 Bad Request` error. ```json theme={null} { "status": 400, "type": "/bad_request", "title": "Bad Request", "detail": "Validation failed", "items": [ { "detail": "The Idempotency-Key header value is not valid." } ] } ``` **Recommended Action**: Ensure your `Idempotency-Key` is present and meets the specified length requirements. ## Best practices 1. **Generate Unique Keys per Business Operation**: For each distinct business operation you initiate, generate a new and unique `Idempotency-Key`. Do not reuse keys across different logical actions. 2. **Use UUIDs**: Universally Unique Identifiers (UUIDs) are an excellent choice for generating idempotency keys due to their high probability of uniqueness. 3. **Handle 409 Conflicts**: Implement logic in your client to properly handle `409 Conflict` responses. For "key already used for a different request," generate a new key. For "previous identical request currently in progress," consider retrying. 4. **Key Length**: Ensure your `Idempotency-Key` is between 10 and 40 characters long. 5. **Avoid Sending Same Key with Different Data**: Never send the same `Idempotency-Key` with a different request body, path, or HTTP method. This results in a `409 Conflict` error. ## Next steps Now that you are familiar with idempotent requests, it's time to start using them. Check out our [API Reference](/api-reference) for detailed information on available endpoints and how to use them. # Straddle API introduction Source: https://docs.straddle.com/api-reference/introduction Get started with the Straddle REST API for ACH and bank payments. Learn the resource model, request and response conventions, and authentication basics. The Straddle API is designed around REST principles. Our API features intuitive, resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and utilizes standard HTTP response codes, authentication, and verbs. ## API environments You can use the Straddle API in sandbox mode, which doesn't affect your live data or interact with real banking networks. It's crucial to use the correct combination of API key and environment URL: * Sandbox API keys must be used with the sandbox environment URL * Production API keys must be used with the production environment URL `https://sandbox.straddle.com`
Use this environment for testing and development. It doesn't affect live data or interact with real banking networks.
`https://production.straddle.com`
Use this environment for live transactions. Be cautious, as this interacts with real banking networks and affects live data.
Using mismatched keys and URLs results in authentication errors. ## Authentication Authentication to the API is performed via HTTP Bearer Auth. Your API key should be included in the `Authorization` header of each request: ``` Authorization: Bearer YOUR_API_KEY ``` ## Request format The Straddle API accepts JSON-encoded request bodies. Make sure to set the `Content-Type` header to `application/json` when sending request data. ## Response format Responses from the Straddle API are always JSON-encoded. Successful responses include a `data` object containing the requested information, while error responses include an `error` object with details about what went wrong. ## API limitations The Straddle API is designed for individual object operations. Bulk updates are not supported, meaning you can work on only one object per request. ## Best practices 1. Always use HTTPS for API requests to ensure data security. 2. Include a unique `Request-Id` header with each request to help with debugging and tracking. 3. Use the `Correlation-Id` header for requests that are part of a larger operation or transaction. 4. Implement proper error handling to gracefully manage API responses. By following these guidelines and understanding the structure of the Straddle API, you'll be well-equipped to build robust integrations with our platform. For detailed information on specific endpoints and request/response structures, refer to the relevant sections of this API reference documentation. ## Download API specification You can also download the raw OpenAPI specification file: [Download OpenAPI Specification](https://straddlepublic.blob.core.windows.net/openapi-specs/openapi.json) # Cancel a linked bank account Source: https://docs.straddle.com/api-reference/linkedbankaccounts/cancel patch /v1/linked_bank_accounts/{linked_bank_account_id}/cancel Cancels an existing linked bank account. This can be used to cancel a linked bank account before it has been reviewed. The linked bank account must be in 'created' status. # Create a linked bank account Source: https://docs.straddle.com/api-reference/linkedbankaccounts/create post /v1/linked_bank_accounts Creates a new linked bank account associated with a Straddle account. This endpoint allows you to associate external bank accounts with a Straddle account for various payment operations such as payment deposits, payout withdrawals, and more. # List linked bank accounts Source: https://docs.straddle.com/api-reference/linkedbankaccounts/list get /v1/linked_bank_accounts Returns a list of bank accounts associated with a specific Straddle account. The linked bank accounts are returned sorted by creation date, with the most recently created appearing first. This endpoint supports pagination to handle accounts with multiple linked bank accounts. # Lookup a linked bank account Source: https://docs.straddle.com/api-reference/linkedbankaccounts/lookup get /v1/linked_bank_accounts/{linked_bank_account_id} Retrieves the details of a linked bank account that has previously been created. Supply the unique linked bank account `id`, and Straddle will return the corresponding information. The response includes masked account details for security purposes. # Unmask a linked bank account Source: https://docs.straddle.com/api-reference/linkedbankaccounts/unmask get /v1/linked_bank_accounts/{linked_bank_account_id}/unmask Retrieves the unmasked details of a linked bank account that has previously been created. Supply the unique linked bank account `id`, and Straddle will return the corresponding information, including sensitive details. This endpoint needs to be enabled by Straddle for your account and should only be used when absolutely necessary. # Update a linked bank account Source: https://docs.straddle.com/api-reference/linkedbankaccounts/update put /v1/linked_bank_accounts/{linked_bank_account_id} Updates an existing linked bank account's information. This can be used to update account details during onboarding or to update metadata associated with the linked account. The linked bank account must be in 'created' or 'onboarding' status. # Attaching metadata to Straddle objects Source: https://docs.straddle.com/api-reference/metadata Attach custom key-value pairs to Straddle customers, charges, and payouts using the metadata field. Learn formatting rules, limits, and use cases. Metadata is a powerful feature in Straddle that allows you to attach custom key-value pairs to various objects. This guide explains how to use metadata effectively, its benefits, and best practices. ## What is metadata? Metadata in Straddle is a set of key-value pairs that you can attach to objects such as customers, charges, payouts, and more. It allows you to store additional, structured information that is important for your business but isn't covered by Straddle's standard fields. Metadata is not used by Straddle for any purpose other than storing on the object for your use in the future. It's purely for your own record-keeping. ## Benefits of using metadata 1. **Custom Data Storage**: Store information specific to your business needs. 2. **Improved Searchability**: Use metadata to filter objects in API requests. 3. **Enhanced Reporting**: Include metadata in exported reports for better analysis. 4. **Integration Flexibility**: Facilitate integrations with other systems by storing external IDs or references. ## How to use metadata You can add metadata when creating or updating objects via the Straddle API. Here are some examples: ### Adding metadata when creating a customer ```bash cURL theme={null} curl https://api.straddle.com/v1/customers \ -H "Authorization: Bearer sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" \ -d email="john@example.com" \ -d metadata[order_id]="6735" \ -d metadata[customer_group]="premium" ``` ```javascript Node.js theme={null} const Straddle = require('straddle'); const straddle = new Straddle('sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); straddle.customers.create({ email: 'john@example.com', metadata: { order_id: '6735', customer_group: 'premium' } }).then(customer => { console.log(customer); }).catch(error => { console.error(error); }); ``` ```python Python theme={null} import straddle straddle.api_key = "sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" customer = straddle.Customer.create( email="john@example.com", metadata={ "order_id": "6735", "customer_group": "premium" } ) print(customer) ``` ### Updating metadata on an existing charge ```bash cURL theme={null} curl https://api.straddle.com/v1/charges/ch_1234567890 \ -H "Authorization: Bearer sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" \ -d metadata[sales_rep]="Jane Doe" \ -d metadata[promotion_code]="SUMMER2023" ``` ```javascript Node.js theme={null} const Straddle = require('straddle'); const straddle = new Straddle('sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); straddle.charges.update('ch_1234567890', { metadata: { sales_rep: 'Jane Doe', promotion_code: 'SUMMER2023' } }).then(charge => { console.log(charge); }).catch(error => { console.error(error); }); ``` ```python Python theme={null} import straddle straddle.api_key = "sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" charge = straddle.Charge.modify( "ch_1234567890", metadata={ "sales_rep": "Jane Doe", "promotion_code": "SUMMER2023" } ) print(charge) ``` ## Retrieving metadata When you retrieve an object via the API, its metadata is included in the response. Here's an example of retrieving a customer: ```bash cURL theme={null} curl https://api.straddle.com/v1/customers/cus_1234567890 \ -H "Authorization: Bearer sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" ``` ```javascript Node.js theme={null} const Straddle = require('straddle'); const straddle = new Straddle('sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); straddle.customers.retrieve('cus_1234567890') .then(customer => { console.log(customer.metadata); }) .catch(error => { console.error(error); }); ``` ```python Python theme={null} import straddle straddle.api_key = "sk_test_51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" customer = straddle.Customer.retrieve("cus_1234567890") print(customer.metadata) ``` ## Best practices 1. **Use Consistent Keys**: Establish a naming convention for your metadata keys and stick to it. 2. **Keep It Simple**: Metadata is best suited for simple key-value pairs. For complex data structures, consider storing a reference ID in metadata and keep the full data in your own database. 3. **Avoid Sensitive Data**: Don't store sensitive information (like credit card numbers or social security numbers) in metadata. 4. **Update Carefully**: When updating metadata, be aware that you're replacing the entire metadata object. To add or modify a single field without affecting others, first retrieve the current metadata, modify it, then update the object with the new metadata. 5. **Use for Searchability**: Leverage metadata for fields you'll want to search or filter by later. ## Limitations * Metadata keys and values must be 80 characters or less. * You can have up to 20 keys in the metadata dictionary. * Metadata is not indexed, so searching large volumes of objects by metadata can be slow. Changes to metadata are not versioned. Once you change a metadata value, you cannot retrieve its previous value. ## Conclusion Metadata is a flexible and powerful feature in Straddle that allows you to customize and extend the platform to fit your specific business needs. Follow these guidelines and best practices to use metadata effectively and enhance your integration with Straddle. For more information on how metadata behaves with specific API endpoints, refer to our [API Reference](/api-reference) documentation. # Create an organization Source: https://docs.straddle.com/api-reference/organizations/create post /v1/organizations Creates a new organization related to your Straddle integration. Organizations can be used to group related accounts and manage permissions across multiple users. # List organizations Source: https://docs.straddle.com/api-reference/organizations/list get /v1/organizations Retrieves a list of organizations associated with your Straddle integration. The organizations are returned sorted by creation date, with the most recently created organizations appearing first. This endpoint supports advanced sorting and filtering options to help you find specific organizations. # Cancel a paykey Source: https://docs.straddle.com/api-reference/paykeys/cancel put /v1/paykeys/{id}/cancel Change a paykey's status to inactive to prevent any new charges or payouts from being created using it. The action cannot be undone. # Accept/Reject a paykey Source: https://docs.straddle.com/api-reference/paykeys/patch_review patch /v1/paykeys/{id}/review Update the status of a paykey when in review status # Lookup a paykey Source: https://docs.straddle.com/api-reference/paykeys/retrieve get /v1/paykeys/{id} Retrieves the details of an existing paykey. Supply the unique paykey `id` and Straddle will return the corresponding paykey record , including the `paykey` token value and masked bank account details. # Reveal a paykey Source: https://docs.straddle.com/api-reference/paykeys/reveal get /v1/paykeys/{id}/reveal Retrieves the details of a paykey that has previously been created. Supply the unique paykey ID that was returned from your previous request, and Straddle will return the corresponding paykey information including the unmasked token. # Review a paykey Source: https://docs.straddle.com/api-reference/paykeys/review get /v1/paykeys/{id}/review Get additional details about a paykey. # Search paykeys Source: https://docs.straddle.com/api-reference/paykeys/search get /v1/paykeys Returns a list of paykeys associated with a Straddle account. This endpoint supports advanced sorting and filtering options. # Unblock a paykey Source: https://docs.straddle.com/api-reference/paykeys/unblock patch /v1/paykeys/{id}/unblock Unblocks a paykey that was previously blocked due to an R29 return code. Only paykeys blocked with R29 returns that have not been previously unblocked are eligible. # Unmask paykey data Source: https://docs.straddle.com/api-reference/paykeys/unmask get /v1/paykeys/{id}/unmasked Retrieves the unmasked details of an existing paykey. Supply the unique paykey `id` and Straddle will return the corresponding paykey record, including the unmasked bank account details. This endpoint needs to be enabled by Straddle for your account and should only be used when absolutely necessary. This endpoint is not enabled by default.

Please contact [compliance@straddle.com](mailto:compliance@straddle.com) to request access.
# Search for all payments Source: https://docs.straddle.com/api-reference/payments/search get /v1/payments Search for payments, including `charges` and `payouts`, using a variety of criteria. This endpoint supports advanced sorting and filtering options. # Upload proof of authorization for a payout Source: https://docs.straddle.com/api-reference/payouts/authorize post /v1/payouts/{id}/authorization Uploads a document as proof of authorization for a payout. Uploading again adds another entry to documents rather than replacing the previous one. # Cancel a payout Source: https://docs.straddle.com/api-reference/payouts/cancel put /v1/payouts/{id}/cancel Cancel a payout to prevent it from being processed. The status of the payout must be `created`, `scheduled`, or `on_hold`. # Create a payout Source: https://docs.straddle.com/api-reference/payouts/create post /v1/payouts Use payouts to send money to your customers. # Hold a payout Source: https://docs.straddle.com/api-reference/payouts/hold put /v1/payouts/{id}/hold Hold a payout to prevent it from being processed. The status of the payout must be `created`, `scheduled`, or `on_hold`. # Release a payout Source: https://docs.straddle.com/api-reference/payouts/release put /v1/payouts/{id}/release Release a payout from a `hold` status to allow it to be rescheduled for processing. # Resubmit a payout Source: https://docs.straddle.com/api-reference/payouts/resubmit post /v1/payouts/{id}/resubmit Retry a failed, reversed, or cancelled ACH credit by creating a new payout linked to the original transaction and retaining payment history. # Lookup a payout Source: https://docs.straddle.com/api-reference/payouts/retrieve get /v1/payouts/{id} Retrieves the details of an existing payout. Supply the unique payout `id` to retrieve the corresponding payout information. # Update a payout Source: https://docs.straddle.com/api-reference/payouts/update put /v1/payouts/{id} Update the details of a payout prior to processing. The status of the payout must be `created`, `scheduled`, or `on_hold`. # Create a representative Source: https://docs.straddle.com/api-reference/representatives/create post /v1/representatives Creates a new representative associated with an account. Representatives are individuals who have legal authority or significant responsibility within the business. # List representatives Source: https://docs.straddle.com/api-reference/representatives/list get /v1/representatives Returns a list of representatives associated with a specific account or organization. The representatives are returned sorted by creation date, with the most recently created representatives appearing first. This endpoint supports advanced sorting and filtering options. # Lookup a representative Source: https://docs.straddle.com/api-reference/representatives/lookup get /v1/representatives/{representative_id} Retrieves the details of an existing representative. Supply the unique representative ID, and Straddle will return the corresponding representative information. # Unmask representative data Source: https://docs.straddle.com/api-reference/representatives/unmask get /v1/representatives/{representative_id}/unmask Retrieves the unmasked details of a representative that has previously been created. Supply the unique representative ID, and Straddle will return the corresponding representative information, including sensitive details. This endpoint requires additional authentication and should be used with caution. # Update a representative Source: https://docs.straddle.com/api-reference/representatives/update put /v1/representatives/{representative_id} Updates an existing representative's information. This can be used to update personal details, contact information, or the relationship to the account or organization. # Tracing API requests with Request-Id Source: https://docs.straddle.com/api-reference/request-id Use Request-Id and Correlation-Id headers to trace, debug, and correlate Straddle API requests across services for faster troubleshooting and support. Request ID and Correlation ID are powerful header tools for debugging and tracing API requests in Straddle. This guide explains what they are, how to use them, and best practices for implementation. ## What are Request ID and Correlation ID? ### Request ID A Request ID is a user-defined identifier in the header of each API request. It helps in tracking and debugging individual API calls. ### Correlation ID A Correlation ID is a user-defined identifier in the header of each API request. It helps in tracing a sequence of operations across multiple systems or services. ## How to use Request ID and Correlation ID You can include Request ID and Correlation ID in your API requests to Straddle by adding specific headers to your HTTP requests. ### Using Request ID and Correlation ID Here's an example of creating a charge using the correct fields as specified in the OpenAPI schema, along with Request ID and Correlation ID: ```bash cURL theme={null} curl https://sandbox.straddle.com/v1/charges \ -H "Authorization: Bearer 51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" \ -H "Request-Id: req_1234567890" \ -H "Correlation-Id: corr_abcdefghij" \ -d paykey="pk_test_TYooMQauvdEDq54NiTphI7jx" \ -d description="Example charge" \ -d amount=1000 \ -d currency="usd" \ -d payment_date="2023-09-15" \ -d consent_type="internet" \ -d "device[ip_address]=192.168.1.1" \ -d external_id="order_12345" \ -d "config[balance_check]=required" ``` ```javascript Node.js theme={null} const Straddle = require('straddle'); const straddle = new Straddle('51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); straddle.charges.create({ paykey: 'pk_test_TYooMQauvdEDq54NiTphI7jx', description: 'Example charge', amount: 1000, currency: 'usd', payment_date: '2023-09-15', consent_type: 'internet', device: { ip_address: '192.168.1.1' }, external_id: 'order_12345', config: { balance_check: 'required' } }, { headers: { 'Request-Id': 'req_1234567890', 'Correlation-Id': 'corr_abcdefghij' } }).then(charge => { console.log(charge); }).catch(error => { console.error(error); }); ``` ```python Python theme={null} import straddle straddle.api_key = "51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" charge = straddle.Charge.create( paykey="pk_test_TYooMQauvdEDq54NiTphI7jx", description="Example charge", amount=1000, currency="usd", payment_date="2023-09-15", consent_type="internet", device={ "ip_address": "192.168.1.1" }, external_id="order_12345", config={ "balance_check": "required" }, headers={ 'Request-Id': 'req_1234567890', 'Correlation-Id': 'corr_abcdefghij' } ) print(charge) ``` Here's an example of creating a customer: ```bash cURL theme={null} curl https://sandbox.straddle.com/v1/customers \ -H "Authorization: Bearer 51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" \ -H "Request-Id: req_0987654321" \ -H "Correlation-Id: corr_klmnopqrst" \ -d name="John Doe" \ -d type="individual" \ -d email="john@example.com" \ -d "address[address1]=123 Main St" \ -d "address[city]=Anytown" \ -d "address[state]=CA" \ -d "address[zip]=12345" \ -d phone="+11234567890" \ -d external_id="cust_12345" \ -d "device[ip_address]=192.168.1.1" \ -d "metadata[customer_group]=premium" ``` ```javascript Node.js theme={null} const Straddle = require('straddle'); const straddle = new Straddle('51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); straddle.customers.create({ name: 'John Doe', type: 'individual', email: 'john@example.com', address: { address1: '123 Main St', city: 'Anytown', state: 'CA', zip: '12345' }, phone: '+11234567890', external_id: 'cust_12345', device: { ip_address: '192.168.1.1' }, metadata: { customer_group: 'premium' } }, { headers: { 'Request-Id': 'req_0987654321', 'Correlation-Id': 'corr_klmnopqrst' } }).then(customer => { console.log(customer); }).catch(error => { console.error(error); }); ``` ```python Python theme={null} import straddle straddle.api_key = "51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1" customer = straddle.Customer.create( name="John Doe", type="individual", email="john@example.com", address={ "address1": "123 Main St", "city": "Anytown", "state": "CA", "zip": "12345" }, phone="+11234567890", external_id="cust_12345", device={ "ip_address": "192.168.1.1" }, metadata={ "customer_group": "premium" }, headers={ 'Request-Id': 'req_0987654321', 'Correlation-Id': 'corr_klmnopqrst' } ) print(customer) ``` ## Retrieving Request ID and Correlation ID Straddle includes the Request ID and Correlation ID (if provided) in the response headers of every API request. * Request ID: `Request-Id` * Correlation ID: `Correlation-Id` You can retrieve these headers from the API response to log them or use them for debugging purposes. ## Best practices 1. **Generate Unique IDs**: Ensure that your Request IDs and Correlation IDs are unique. UUIDs are a good choice for this. 2. **Consistent Usage**: Use Request IDs for every API call, and use Correlation IDs for all requests related to a single operation or transaction. 3. **Logging**: Log both Request IDs and Correlation IDs in your application logs. This makes it easier to trace requests across your systems and Straddle. 4. **Error Handling**: Include the Request ID and Correlation ID when logging errors or exceptions. This helps in debugging issues more effectively. 5. **Support Communication**: When contacting Straddle support about a specific API request, always include the Request ID and Correlation ID (if applicable). ## Implementation example Here's an example of how you might implement Request ID and Correlation ID in a real-world scenario: ```javascript Node.js theme={null} const Straddle = require('straddle'); const { v4: uuidv4 } = require('uuid'); const straddle = new Straddle('51NBBbbDBkrcnHrnR0nBGsOvFHQrM0n8T1FKZmAUWbJqq8oRsAM3dEZzBIbHwzKrVUUFOyRvX1Ib8Sn3VWWQMW00r300IIrGBWb1'); async function processOrder(orderDetails) { const correlationId = uuidv4(); try { // Create customer const customer = await straddle.customers.create({ name: orderDetails.name, type: 'individual', email: orderDetails.email, phone: orderDetails.phone, external_id: orderDetails.customerId, device: { ip_address: orderDetails.ipAddress } }, { headers: { 'Correlation-Id': correlationId, 'Request-Id': uuidv4() } }); // Create charge const charge = await straddle.charges.create({ paykey: orderDetails.paykey, amount: orderDetails.amount, currency: orderDetails.currency, payment_date: new Date().toISOString().split('T')[0], // Today's date consent_type: 'internet', device: { ip_address: orderDetails.ipAddress }, external_id: orderDetails.orderId }, { headers: { 'Correlation-Id': correlationId, 'Request-Id': uuidv4() } }); console.log(`Order processed successfully. Charge ID: ${charge.id}`); } catch (error) { console.error(`Error processing order. Correlation ID: ${correlationId}`, error); } } processOrder({ name: 'Jane Smith', email: 'jane@example.com', phone: '+11234567890', customerId: 'cust_67890', ipAddress: '192.168.1.1', amount: 2000, currency: 'usd', paykey: 'TYooMQauvdEDq54NiTphI7jx', orderId: 'order_54321' }); ``` In this example, you generate a unique Correlation ID for the entire order processing operation, and unique Request IDs for each API call. This allows you to trace the entire order process across multiple API calls. ## Conclusion Using Request ID and Correlation ID effectively can significantly improve your ability to debug and trace API requests when integrating with Straddle. These best practices help you monitor your integration, troubleshoot issues, and communicate effectively with Straddle support when needed. For more information on how Request ID and Correlation ID behave with specific API endpoints, refer to our [API Reference](/api-reference) documentation. # Straddle API response format Source: https://docs.straddle.com/api-reference/response-structure Understand the JSON envelope for Straddle API responses, including the data, meta, and error fields, plus pagination metadata for list endpoints. Understanding the structure of API responses is crucial for effectively integrating with the Straddle API. This guide outlines the standard format for successful requests, paginated responses, and error responses. ## Successful requests For successful requests, the Straddle API returns a JSON object with the following structure: * `meta`: Contains metadata about the request. * `response_type`: Indicates the type of data returned (e.g., "object" or "array"). * `data`: Contains the actual payload of the response. ### Example: Single object response ```json JSON theme={null} { "meta": { "api_request_id": "f1b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b" }, "response_type": "object", "data": { "id": "1", "name": "John Doe", "email": "john.doe@gmail.com", "dob": "1980-01-01", "address": { "street": "123 Main St", "city": "Anytown", "state": "NY", "zip": "12345" } } } ``` ### Key points * The `data` property contains the main payload. * `response_type` is set to "object" for single item responses. * Field names use whole words, except for common acronyms (e.g., dob, SSN, URL). * IDs are represented as strings. ## Paginated responses For requests that return lists of data (e.g., a list of customers), the response structure is similar but includes pagination information: * `data` contains an array of objects, typically with summarized information. * `response_type` is set to "array". * `meta` includes additional pagination-related information. ### Example: Paginated response ```json JSON theme={null} { "meta": { "api_request_id": "f1b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b", "page_number": 4, "page_size": 50, "total_items": 1500, "sort_order": "asc", "sort_by": "name" }, "response_type": "array", "data": [ { "id": "c1b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b", "label": "John Doe", "name": "John Doe", "email": "john.doe@gmail.com" }, { "id": "a9b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b", "name": "Steven Martin", "email": "steve@martinco.com" }, { "id": "f6b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b", "name": "John Doe", "email": "john.doe@gmail.com" } ] } ``` ### Pagination metadata The `meta` object in paginated responses includes: * `page_number`: Current page number * `page_size`: Number of items per page * `total_items`: Total number of items across all pages * `sort_order`: Sorting order ("asc" or "desc") * `sort_by`: Field used for sorting ## Failed requests For failed requests, the Straddle API uses HTTP status codes to indicate the nature of the error: * 4xx status codes: Used for client-side errors (e.g., validation errors, permission issues) * 5xx status codes: Used for server-side errors The response structure for errors is different from successful requests: * There is no `data` property. * `response_type` is set to "error". * An `error` object provides details about the error. ### Example: Error response ```json JSON theme={null} { "meta": { "api_request_id": "f1b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b" }, "response_type": "error", "error": { "status": 400, "type": "/field_validation", "title": "Invalid input data", "detail": "The request contains invalid field values", "items": [ { "reference": "#WS01", "detail": "Payment window has closed for the day." }, { "reference": "representative/2/email", "detail": "Email address must be unique" }, { "reference": "representative/3/email", "detail": "Email address must be unique" } ] } } ``` ### Error object structure The `error` object in error responses includes: * `status`: HTTP status code (integer) * `type`: Predefined general type of error (e.g., "/field\_validation") * `title`: Generic message for this type of issue * `detail`: Specific message regarding this exact request * `items`: Array of error objects with more specific details Each error item in the `items` array contains: * `reference`: Identifier for the error (e.g., field name, error code) * `detail`: Detailed description of the specific error ## Best practices for handling responses 1. **Check `response_type`**: Always check the `response_type` to determine how to parse the response. 2. **Handle Pagination**: When working with paginated responses, use the metadata to implement proper pagination in your application. 3. **Error Handling**: Parse the `error` object in failed requests to provide meaningful feedback to users or for debugging. 4. **Use `api_request_id`**: Log the `api_request_id` for all requests. This is crucial for troubleshooting and communicating with Straddle support. 5. **Parsing Data**: When working with successful responses, always access the payload through the `data` property. ## Conclusion Understanding the Straddle API response format is key to building robust integrations. By following this structure, you can effectively handle successful responses, paginate through large datasets, and gracefully manage errors in your applications. For more detailed information on specific API endpoints and their responses, refer to our [API Reference](/api-reference) documentation. # Node.js SDK for Straddle Source: https://docs.straddle.com/api-reference/sdk/node Install and configure the official Straddle Node.js SDK. Authenticate, make API calls, handle errors, and integrate ACH payments in JavaScript or TypeScript. The Straddle Node.js SDK provides type-safe access to the Straddle API, with built-in TypeScript support and convenient methods for all API operations. The SDK includes comprehensive TypeScript definitions and supports all modern JavaScript environments including Node.js, Deno, and Bun. ## Installation Install the SDK using npm: ```bash theme={null} npm install @straddlecom/straddle ``` Or using yarn: ```bash theme={null} yarn add @straddlecom/straddle ``` ## Setup and configuration Import the appropriate client based on your needs: ```typescript theme={null} import Straddle from '@straddlecom/straddle'; ``` Create a new instance of the Straddle client: ```typescript theme={null} const client = new Straddle({ apiKey: process.env['STRADDLE_API_KEY'], environment: 'sandbox', // or 'production' }); ``` Never hardcode your API key directly in your code. Use environment variables or a secure configuration management system. ## Implementation examples For account customers (non-platform), the flow is simpler as the account context is inferred from the API key: ```typescript theme={null} import Straddle from '@straddlecom/straddle'; async function accountFlow() { const client = new Straddle({ apiKey: process.env['STRADDLE_API_KEY'], environment: 'sandbox' }); // 1. Create a customer const customer_response = await client.customers.create({ device: { ip_address: '192.168.0.1' }, email: 'customer@example.com', name: 'Customer Name', phone: '+15555555555', type: 'individual' }); const customer = customer_response.data; // 2. Link a bank account const paykey_response = await client.bridge.link.bankAccount({ customer_id: customer.id, routing_number: '011000028', account_number: '000123456789', account_type: 'checking' }); const paykey = paykey_response.data; // 3. Create a charge const charge = await client.charges.create({ amount: 1, config: { balance_check: 'required' }, consent_type: 'internet', currency: 'USD', description: 'Monthly subscription fee', device: { ip_address: '192.168.1.1' }, external_id: 'external_id', paykey: paykey.paykey, payment_date: '2025-01-30' }); } accountFlow().catch(console.error); ``` This example demonstrates the complete flow for Embed customers: ```typescript theme={null} import Straddle from '@straddlecom/straddle'; async function embedFlow() { const client = new Straddle({ apiKey: process.env['STRADDLE_API_KEY'], environment: 'sandbox' }); // 1. Create an organization const org_response = await client.embed.organizations.create({ name: 'SDK Test Organization in Sandbox' }); const organization = org_response.data; // 2. Create an account for the organization const account_response = await client.embed.accounts.create({ organization_id: organization.id, account_type: 'business', business_profile: { name: 'Last SDK Test', website: 'straddle.com' }, access_level: 'standard' }); const account = account_response.data; // 3. Create a customer const customer_response = await client.customers.create({ "Straddle-Account-Id": account.id, device: { ip_address: '192.168.0.1' }, email: 'customer@example.com', name: 'Customer Name', phone: '+15555555555', type: 'individual' }); const customer = customer_response.data; // 4. Link a bank account const paykey_response = await client.bridge.link.bankAccount({ "Straddle-Account-Id": account.id, customer_id: customer.id, routing_number: '011000028', account_number: '000123456789', account_type: 'checking' }); const paykey = paykey_response.data; // 5. Create a charge const charge = await client.charges.create({ "Straddle-Account-Id": account.id, amount: 1, config: { balance_check: 'required' }, consent_type: 'internet', currency: 'USD', description: 'Monthly subscription fee', device: { ip_address: '192.168.1.1' }, external_id: 'external_id', paykey: paykey.paykey, payment_date: '2025-01-30' }); console.log(charge.data); } embedFlow().catch(console.error); ``` ## Key features Complete TypeScript definitions for all request params and response fields, providing excellent IDE support. Modern promise-based API with async/await support for clean, readable code. Built-in support for automatic pagination, making it easy to handle large result sets. Comprehensive error types and helpful error messages for better debugging and error recovery. ## Error handling The SDK provides specific exception types for different error cases: ```typescript theme={null} try { const charge = await client.charges.create({ amount: 1000, currency: 'USD', // ... other required params }); } catch (error) { if (error instanceof Straddle.APIError) { console.log(error.status); // HTTP status code console.log(error.message); // Error message } } ``` Common error types include: * `BadRequestError` (400) * `UnprocessableEntityError` (422) * `AuthenticationError` (401) * `PermissionDeniedError` (403) * `NotFoundError` (404) * `RateLimitError` (429) * `InternalServerError` (>500) Configure request timeouts: ```typescript theme={null} // Simple timeout const client = new Straddle({ timeout: 20 * 1000 // 20 seconds }); // Per-request timeout await client.charges.create({ // ... params }, { timeout: 5 * 1000 // 5 seconds }); ``` ## SDK requirements Node.js 18 LTS or higher TypeScript >= 4.5 For more detailed information about the SDK structure and usage, refer to our [NPM Package](https://www.npmjs.com/package/@straddlecom/straddle). # Python SDK for Straddle Source: https://docs.straddle.com/api-reference/sdk/python Install and configure the official Straddle Python SDK. Authenticate, make API calls, handle errors, and integrate ACH payments into your Python application. The Straddle Python SDK provides convenient access to the Straddle API from any Python application. The SDK includes type definitions and offers both synchronous and asynchronous clients powered by httpx. The SDK supports Python 3.8+ and provides comprehensive type hints through TypedDict and Pydantic models. ## Installation Install the SDK using pip: ```bash theme={null} pip install straddle ``` For development environments, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) to manage your API keys: ```bash theme={null} pip install python-dotenv ``` ## Setup and configuration Import the appropriate client based on your needs: ```python theme={null} from straddle import AsyncStraddle ``` Create a new instance of the Straddle client: ```python theme={null} client = AsyncStraddle( api_key=os.environ.get("STRADDLE_API_KEY"), environment="sandbox", # or "production" ) ``` Never hardcode your API key directly in your code. Use environment variables or a secure configuration management system. ## Implementation examples For account customers (non-platform), the flow is simpler as the account context is inferred from the API key: ```python theme={null} import asyncio from straddle import AsyncStraddle from pydantic.v1.datetime_parse import parse_date from straddle.types import DeviceUnmaskedV1Param async def account_flow(): client = AsyncStraddle( api_key=os.environ.get("STRADDLE_API_KEY"), environment="sandbox" ) # 1. Create a customer customer_response = await client.customers.create( device=DeviceUnmaskedV1Param(ip_address="192.168.0.1"), email="customer@example.com", name="Customer Name", phone="+15555555555", type="individual" ) customer = customer_response.data # 2. Link a bank account paykey_response = await client.bridge.link.bank_account( customer_id=customer.id, routing_number="011000028", account_number="000123456789", account_type="checking" ) paykey = paykey_response.data # 3. Create a charge charge = await client.charges.create( amount=1, config={"balance_check": "required"}, consent_type="internet", currency="USD", description="Monthly subscription fee", device={"ip_address": "192.168.1.1"}, external_id="external_id", paykey=paykey.paykey, payment_date=parse_date("2025-01-30") ) print(charge.data) if __name__ == '__main__': asyncio.run(account_flow()) ``` This example demonstrates the complete flow for Embed customers using the async client: ```python theme={null} import asyncio from straddle import AsyncStraddle from pydantic.v1.datetime_parse import parse_date from straddle.types import DeviceUnmaskedV1Param from straddle.types.embed import BusinessProfileV1Param async def embed_flow(): client = AsyncStraddle( api_key=os.environ.get("STRADDLE_API_KEY"), environment="sandbox" ) # 1. Create an organization org_response = await client.embed.organizations.create( name="SDK Test Organization in Sandbox", ) organization = org_response.data # 2. Create an account for the organization account_response = await client.embed.accounts.create( organization_id=organization.id, account_type="business", business_profile=BusinessProfileV1Param( name="SDK Test", website="straddle.com" ), access_level="standard" ) account = account_response.data # 3. Create a customer customer_response = await client.customers.create( straddle_account_id=account.id, device=DeviceUnmaskedV1Param(ip_address="192.168.0.1"), email="customer@example.com", name="Customer Name", phone="+15555555555", type="individual" ) customer = customer_response.data # 4. Link a bank account paykey_response = await client.bridge.link.bank_account( straddle_account_id=account.id, customer_id=customer.id, routing_number="011000028", account_number="000123456789", account_type="checking" ) paykey = paykey_response.data # 5. Create a charge charge = await client.charges.create( straddle_account_id=account.id, amount=1, config={"balance_check": "required"}, consent_type="internet", currency="USD", description="Monthly subscription fee", device={"ip_address": "192.168.1.1"}, external_id="external_id", paykey=paykey.paykey, payment_date=parse_date("2025-01-30"), ) print(charge.data) if __name__ == '__main__': asyncio.run(embed_flow()) ``` ## Key features Built-in type hints with TypedDict for requests and Pydantic models for responses, providing excellent IDE support and catching errors early. First-class async/await support through the AsyncStraddle client, perfect for high-performance applications. Built-in support for automatic pagination, making it easy to handle large result sets. Comprehensive error types and helpful error messages for better debugging and error recovery. ## Error handling The SDK provides specific exception types for different error cases: ```python theme={null} try: charge = await client.charges.create( amount=1000, currency="USD", # ... other required params ) except straddle.APIConnectionError as e: print("Connection error:", e.__cause__) except straddle.RateLimitError as e: print("Rate limit exceeded:", e.status_code) except straddle.APIStatusError as e: print("API error:", e.status_code) print("Response:", e.response) ``` Common error types include: * `BadRequestError` (400) * `UnprocessableEntityError` (422) * `AuthenticationError` (401) * `PermissionDeniedError` (403) * `NotFoundError` (404) * `RateLimitError` (429) * `InternalServerError` (>500) Configure request timeouts: ```python theme={null} import httpx # Simple timeout client = AsyncStraddle(timeout=20.0) # 20 seconds # Detailed timeout configuration client = AsyncStraddle( timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0) ) ``` ## SDK requirements Python 3.8 or higher For more detailed information about the SDK structure and usage, refer to our [Pypi Package](https://pypi.org/project/straddle/). # Ruby SDK for Straddle Source: https://docs.straddle.com/api-reference/sdk/ruby Install and configure the official Straddle Ruby SDK. Authenticate, make API calls, handle errors, and integrate ACH payments into your Ruby application. The Straddle Ruby library provides convenient access to the Straddle REST API from any Ruby 3.2.0+ application. The library includes comprehensive support for all API endpoints with built-in error handling. The SDK supports Ruby 3.2.0+ and provides a clean, idiomatic Ruby interface to the Straddle API. ## Installation Install the SDK by adding it to your application's `Gemfile`: ```ruby theme={null} gem "straddle" ``` Then run: ```bash theme={null} bundle install ``` For development environments, we recommend using [dotenv](https://github.com/bkeepers/dotenv) to manage your API keys: ```ruby theme={null} gem "dotenv", groups: [:development, :test] ``` ## Setup and configuration Require the necessary gems in your Ruby application: ```ruby theme={null} require "bundler/setup" require "straddle" ``` Create a new instance of the Straddle client: ```ruby theme={null} straddle = Straddle::Client.new( api_key: ENV["STRADDLE_API_KEY"], # This is the default and can be omitted environment: "sandbox" # or "production", defaults to "sandbox" ) ``` Never hardcode your API key directly in your code. Use environment variables or a secure configuration management system. ## Implementation examples The Straddle Ruby SDK uses symbols for hash keys in method parameters. This follows Ruby conventions and provides better performance than string keys. For account customers (non-platform), the flow is simpler as the account context is inferred from the API key: ```ruby theme={null} require "bundler/setup" require "straddle" # Initialize the client straddle = Straddle::Client.new( api_key: ENV["STRADDLE_API_KEY"], environment: "sandbox" ) # 1. Create a customer customer_response = straddle.customers.create( device: { ip_address: "192.168.0.1" }, email: "customer@example.com", name: "Customer Name", phone: "+15555555555", type: "individual" ) customer = customer_response.data # 2. Link a bank account paykey_response = straddle.bridge.link.bank_account( customer_id: customer.id, routing_number: "011000028", account_number: "000123456789", account_type: "checking" ) paykey = paykey_response.data # 3. Create a charge charge = straddle.charges.create( amount: 100, # Amount in cents ($1.00) config: { balance_check: "required" }, consent_type: "internet", currency: "USD", description: "Monthly subscription fee", device: { ip_address: "192.168.1.1" }, external_id: "external_id", paykey: paykey.paykey, payment_date: "2025-01-30" # Can also use Date objects: Date.new(2025, 1, 30) # Can also use Date objects: Date.new(2025, 1, 30) ) puts charge.data ``` This example demonstrates the complete flow for Embed customers: ```ruby theme={null} require "bundler/setup" require "straddle" # Initialize the client straddle = Straddle::Client.new( api_key: ENV["STRADDLE_API_KEY"], environment: "sandbox" ) # 1. Create an organization org_response = straddle.embed.organizations.create( name: "SDK Test Organization in Sandbox" ) organization = org_response.data # 2. Create an account for the organization account_response = straddle.embed.accounts.create( organization_id: organization.id, account_type: "business", business_profile: { name: "SDK Test", website: "straddle.com" }, access_level: "standard" ) account = account_response.data # 3. Create a customer customer_response = straddle.customers.create( straddle_account_id: account.id, device: { ip_address: "192.168.0.1" }, email: "customer@example.com", name: "Customer Name", phone: "+15555555555", type: "individual" ) customer = customer_response.data # 4. Link a bank account paykey_response = straddle.bridge.link.bank_account( straddle_account_id: account.id, customer_id: customer.id, routing_number: "011000028", account_number: "000123456789", account_type: "checking" ) paykey = paykey_response.data # 5. Create a charge charge = straddle.charges.create( straddle_account_id: account.id, amount: 100, # Amount in cents ($1.00) config: { balance_check: "required" }, consent_type: "internet", currency: "USD", description: "Monthly subscription fee", device: { ip_address: "192.168.1.1" }, external_id: "external_id", paykey: paykey.paykey, payment_date: "2025-01-30" ) puts charge.data ``` ## Key features Clean, Ruby-style interface following community conventions with snake\_case methods and intuitive hash parameters. The client is thread-safe, allowing you to share a single instance across multiple threads in your application. Built-in retry logic for transient errors with configurable retry strategies. Comprehensive error classes that map to HTTP status codes for precise error handling. ## Error handling The SDK provides specific exception types for different error cases: ```ruby theme={null} begin charge = straddle.charges.create( amount: 1000, currency: "USD", # ... other required params ) rescue Straddle::Errors::BadRequestError => e puts "Bad request: #{e.message}" puts "Status: #{e.status_code}" puts "Response body: #{e.response_body}" if e.respond_to?(:response_body) rescue Straddle::Errors::UnprocessableEntityError => e puts "Validation error: #{e.message}" puts "Errors: #{e.errors}" if e.respond_to?(:errors) rescue Straddle::Errors::AuthenticationError => e puts "Authentication failed: #{e.message}" rescue Straddle::Errors::PermissionDeniedError => e puts "Permission denied: #{e.message}" rescue Straddle::Errors::NotFoundError => e puts "Resource not found: #{e.message}" rescue Straddle::Errors::RateLimitError => e puts "Rate limit exceeded: #{e.message}" puts "Retry after: #{e.retry_after}" if e.respond_to?(:retry_after) rescue Straddle::Errors::InternalServerError => e puts "Server error: #{e.message}" rescue Straddle::Errors::APIError => e # Catch all other API errors puts "API error: #{e.message}" end ``` Common error types include: * `BadRequestError` (400) * `UnprocessableEntityError` (422) * `AuthenticationError` (401) * `PermissionDeniedError` (403) * `NotFoundError` (404) * `RateLimitError` (429) * `InternalServerError` (>=500) Configure request timeouts: ```ruby theme={null} # Configure timeout in seconds straddle = Straddle::Client.new( api_key: ENV["STRADDLE_API_KEY"], timeout: 30 # 30 seconds ) # Or configure with more granular settings straddle = Straddle::Client.new( api_key: ENV["STRADDLE_API_KEY"], timeout: { connect: 5, read: 30, write: 10 } ) ``` Configure automatic retries: ```ruby theme={null} straddle = Straddle::Client.new( api_key: ENV["STRADDLE_API_KEY"], max_retries: 3, retry_delay: 1.0 # seconds ) ``` ## SDK requirements Ruby 3.2.0 or higher Bundler for dependency management For more detailed information about the SDK structure and usage, refer to our [API Documentation](https://docs.straddle.com) and [GitHub repository](https://github.com/straddleio/straddle-ruby). # 2024 changelog and product updates Source: https://docs.straddle.com/changelog/updates/2024 Product updates, new features, and platform announcements for the Straddle ACH payments and identity verification platform throughout 2024. > Keep track of Straddle's latest updates and improvements ## Integrations * **Direct Webhook Connections:** Route Straddle notifications directly to Slack, Microsoft Teams, Discord, and HubSpot without needing custom HTTP endpoints. Learn more on the [Integrations page](/integrations/overview). ## Documentation * **Plaid Link Guide:** Published a [step-by-step guide](/integrations/open-banking/plaid) for connecting Straddle with Plaid Link. ## Announcing Straddle! We're excited to announce the public launch of Straddle! We're building modern account-to-account payments that actually work, handling the full stack from identity verification to open banking connections to money movement. ## Community * **Developer Slack Launched:** We launched our [developer community on Slack](https://straddlers.slack.com) - a space for real talk, early access, code samples, and shaping our roadmap. Join us! ## Security & Compliance * **SOC 2 Type II Certified:** We achieved our SOC 2 Type II certification, proving our commitment to security. View the report in our [Trust Center](https://trust.straddle.com/item/soc-2-type-ii-attestation). # 2025 changelog and product updates Source: https://docs.straddle.com/changelog/updates/2025 Product updates, new features, and platform announcements for the Straddle ACH payments and identity verification platform throughout 2025. # We build for you. **You'll See Fewer Paykey Rejections** You can now manually review certain Paykeys that would normally auto-reject. These paykeys are created with a `review` status, allowing you to `accept` or `reject` them either in the dashboard or programmatically via our API. Screenshot2025 11 05at11 28 16AM Pn **Get the Full Picture on Every Verification** Retrieve comprehensive verification data to understand the "why" behind every paykey status and streamline your approval workflow. ```json theme={null} "verificationDetails": { "id": "456e7890-e89b-12d3-a456-426614174001", "decision": "review", "messages": { "NM01": "Account Holder is not a match for Customer." }, "codes": ["NM01"], "breakdown": { "nameMatch": { "decision": "review", "reason": "Account Holder is not a match for Customer.", "matchedName": "John Smith", "correlationScore": 0.21, "namesOnAccount": ["John Smith", "Jane Smith"] } ``` **Account Balance Updates** For accounts linked using an open banking token or Bridge, you can now receive balance updates when the following events occur: * When a new Paykey is created * When the new refresh endpoint is explicitly called, at most once per hour * When a charge or payout is created, if the balance was last updated more than one hour ago You will receive the balance update within [Paykey webhook events](https://straddle.dev/api-reference#webhook/post/paykeyeventv1). **Trigger Re-Verification** You are able to set the paykey's status back to pending triggering automated re-verification. **Sandbox Outcome for Paykey Review Status** To test the new review status, set the sandbox outcome to "review" when creating a Paykey. Check out this guide to learn more: [Paykey Guide](https://docs.straddle.io/guides/bridge/paykeys) ## Idempotent requests and custom metadata * You can now add custom `metadata` when creating or updating representatives. This `metadata` will be included in the response when retrieving `representative` details via a GET request. * To prevent duplicate requests, we've introduced idempotent requests. Include a unique `Idempotency-Key` header in your HTTP requests to utilize this feature. * We've added dark mode to the onboarding form. It'll automatically match whatever theme you're using on your device. ## Ruby SDK and overall updates * We've released a new version of our existing Node and Python SDKs. * We've added a new Ruby SDK for Straddle, check it out here: [Ruby SDK](/api-reference/sdk/ruby). ## Sandbox Simulations * We've improved the ability to simulate various scenarios in the sandbox environment when integrating with Straddle. Follow this guide to learn more about it [Sandbox Simulations](/guides/resources/sandbox-paybybank). ## Quiltt Integration * We've built a new integration to our Open Banking stack with our partner [Quiltt](https://www.quiltt.io/). This allows you to bring your existing Open Banking connections from **Quiltt Connector** to integrate with Straddle using the [Straddle Bridge API](/guides/bridge/quiltt-token). ## Zapier Integration * You can now integrate Straddle with Zapier to trigger automated workflows when events occur in Straddle. Check out the new docs for [Zapier integration](/integrations/webhooks/zapier). ## Straddle Reputation We're excited to introduce Straddle Reputation, a powerful new fraud prevention system that leverages consortium data to identify repeat bad actors and stop friendly fraud before it happens. Identity Sv ### What's New **Data-driven Fraud Detection** Access risk signals derived from a vast network of financial institutions, fintechs, neobanks, lenders, gaming platforms, and telcos across the US. **Friendly Fraudster Identification** Identify consumers with histories of fraudulent activities across multiple institutions before they can harm your business. **Reputation Risk Score** Receive a numerical risk score specifically designed to identify repeat bad actors, enabling more informed decisioning. **Historical Insights** Access detailed transaction history metrics including ACH fraud, card disputes, account closures, and more to understand the full context of risk signals. **Reputation Codes** Interpret risk with specific reason codes that explain exactly which risk factors were identified for a consumer identity. **Built Into Customer Profiles** Reputation data is automatically integrated into every customer profile, providing seamless access to risk intelligence throughout your payment flows. **New Documentation** [**How Straddle Reputation helps fight friendly fraud**](https://docs.straddle.com/guides/identity/reputation) ## Marketplace Platforms We've evolved Straddle Embed to support two distinct platform types with different customer relationship models. ### What's New [**Marketplace Platforms**](https://docs.straddle.com/guides/embed/overview#marketplace-platform-model) A new model enabling platform-level [customers](https://docs.straddle.com/guides/identity/customers) who can transact with multiple accounts (sellers). [**SaaS Platform**](https://docs.straddle.com/guides/embed/overview#saas-platform-model) Maintains the existing 1:1 customer-to-account relationship for vertical SaaS providers whose end users interact with individual businesses. **Platform-Level Customers** Marketplace platforms can now create customers at the platform level with centralized profiles, allowing seamless transactions across multiple sellers. **New Documentation** Learn more about both models in our [Straddle Embed: Platform Guide](https://docs.straddle.com/guides/embed/overview). ## Payment Reporting API We've launched a powerful new reporting endpoint that makes it easier to search, filter, and analyze your payment data. ### What's New **Unified Payment Search** Search across both charges and payouts with a single API endpoint, simplifying how you access and analyze your payment data. **Advanced Filtering** Filter payments by type, status, amount ranges, date ranges, customer IDs, and more to find exactly the transactions you need. **Flexible Sorting** Sort results by created date, payment date, effective date, amount, or ID in ascending or descending order. **Pagination Support** Control result set size with customizable page size and pagination to efficiently process large datasets. **Full-Text Search** Find payments using free-text search across relevant payment fields for quick information retrieval. **New Documentation** Check out the new reporting endpoint in our [API Reference](https://docs.straddle.com/api-reference/payments/search). ## API Logs Introducing detailed and searchable API logs within the Straddle Dashboard to help you monitor and troubleshoot your integration. Apilogs Web ### What's New **Advanced Search and Filtering** Find the exact requests you need with powerful filtering by method, status code, timestamp, and duration. **Faster Troubleshooting** Identify and resolve integration issues more efficiently with complete request/response data and status codes available in real time. **Improved Observability** Quickly identify bottlenecks or errors across your payment flows with comprehensive performance metrics and response times. **Historical Data Access** Access up to 30 days of historical API logs to track down intermittent issues or analyze usage patterns over time. ## Dashboard V2 We've completely rebuilt the [Straddle dashboard](https://dashboard.straddle.com) from the ground up, focusing on developer experience, workflow efficiency, and powerful insights to help your team move faster. ### What's New **Work smarter, not harder** Navigate with confidence through our intuitive layout designed for developer productivity. Access critical information with fewer clicks. **Business metrics** Transform complex data into actionable insights with our improved interactive charts, real-time metrics, and comprehensive reporting tools. Spot trends faster and make data-driven decisions with confidence. **Built for speed** Experience lightning-fast response times with our rebuilt architecture. Page loads are up to 70% faster, API responses are optimized, and resource utilization is significantly reduced. ## Business Identity and Chargeback Protection We've expanded our identity verification capabilities with a comprehensive solution specifically for business customers. Biz Sv ### What's New **Business Verification Engine** Verify business customers with advanced checks for EIN, legal business name, business address, and people associated with the business. **Business Identity Codes** New "BI" prefixed verification codes provide detailed insights into verification results across multiple categories including tax ID verification, address verification, entity type, and business standing. **Chargeback Protection** Businesses using Business Identity verification now receive chargeback protection after 48 hours for verified business customers. **Risk Scoring** Numerical risk scores from 0 to 1 help assess business verification status for more intelligent decision-making. **New Documentation** Learn more about integrating and interpreting Business Identity in our [Business Identity guide](/guides/identity/business_identity). ## SDKs * **Python SDK:** Launched the [Straddle Python SDK](/api-reference/sdk/python) with type definitions and sync/async clients. * **Node.js SDK:** Launched the [Straddle Node.js SDK](/api-reference/sdk/node) with TypeScript support for Node.js, Deno, and Bun. ## Webhooks * **Polling Endpoints:** Added the ability to get a stream of events by [polling webhook endpoints](/webhooks/overview/polling), useful for local testing or batch processing. * **Storage Integrations:** Send Straddle webhook data directly to AWS S3, Azure Blob Storage, or Google Cloud Storage. ## Developer Tools * **Interactive Playground:** Launched a new interactive developer playground at [straddle.dev](https://straddle.dev). * **Postman Collection:** Published an official Postman collection at [https://www.postman.com/strddl](https://www.postman.com/strddl). ## Website * **New Marketing Site:** Launched a revamped marketing site at [straddle.com](https://straddle.com) with clearer product explanations. ## Platform * **API Status Page:** Launched a dedicated API status page at [status.straddle.com](https://status.straddle.com) with support for email/webhook subscriptions. # 2026 changelog and product updates Source: https://docs.straddle.com/changelog/updates/2026 Product updates, new features, and platform announcements for the Straddle ACH payments and identity verification platform throughout 2026. # We build for you. **Webhooks and dashboard actions in Trace** Trace now shows the webhooks Straddle sent for an entity and the actions your team took on it in the dashboard, next to its API calls and status changes. Every event that touched the entity reads in order on one timeline. Calls and dashboard actions show whether a user or an API key made them. Filter the timeline to **API logs**, **User logs**, **Webhooks**, or **Entity history** to read one source at a time, and click a webhook row to see the payload your endpoint received. **Readable traces for busy entities** A funding event can carry hundreds of payouts. When an entity has three or more related entities of one kind, Trace keeps the three most recent on the graph and groups the rest into a cluster. Open the cluster to page through its members and add the ones you need to the graph. **A rebuilt timeline and event lanes** Each timeline row shows how long after the start of the trace it happened, what kind of event it is, and which entity it belongs to. Select a row to open its full details in a side panel. In **Event lanes**, columns cover only the stretches of time that had activity, and you can collapse a lane to a strip that marks where its events fall. Times display in your time zone, with Eastern Time on hover. **User Logs** [User Logs](https://dashboard.straddle.com/user-logs) lists every action people took in the dashboard, such as **Refund Charge** or **Review Paykey**, with the endpoint it called underneath. Search the list, sort by time or duration, and filter by user, method, or outcome. Click a user's name to see only their actions, or click an API key on API Logs to do the same for that key. Open User Logs from the developer menu in the dashboard header. Trace and User Logs are available to users with the developer or admin role. **Product announcements in the dashboard** New Straddle features now appear as a card in the bottom-right corner of the [Straddle Dashboard](https://dashboard.straddle.com), so you hear about them without checking the changelog. Each card links to the full changelog entry. Dismiss a card and it won't appear again for you. When more than one announcement is waiting, the card shows the newest first, and its arrows step through the rest. **Handle Paykeys in Review from Bridge** The Bridge widget's `onSuccess` callback can now return paykeys with either an `active` or `review` status. A successful callback confirms that the paykey was created, but does not guarantee that it is active. Always inspect `payload.data.status`. Paykeys in `review` require approval or rejection in the Dashboard or through the API, and payments submitted with them remain on hold until the review is resolved. See the [Bridge widget guide](/guides/bridge/widget#3-handle-the-widget-callback) for integration guidance. **Trace** When a payment fails, the explanation is rarely on the payment. It's in what came before: when the customer was created, when the paykey was added, what changed along the way. Open any customer, paykey, charge, payout, or funding event in the [Straddle Dashboard](https://dashboard.straddle.com) and click **Trace logs** to get all of it on one timeline. A graph of the connected entities sits beside it. * **Understand one customer.** Follow a customer through every paykey, payment, and status change tied to them, without opening five pages to do it. * **Find the root cause.** Read the sequence that produced a failure instead of working backwards from the final status. Click a row for the full request and response, a node to follow the chain, or switch to **Event lanes** for one lane per entity on a shared clock. You can also start from an ID at [Trace](https://dashboard.straddle.com/trace). See the [dashboard walkthrough](https://help.straddle.com/article/how-to-trace-an-entity-in-the-dashboard). Trace on a failed charge: a graph of the charge with its paykey and customer, beside a timeline of what happened **Universal search** Find any charge, payout, customer, paykey, account, or funding event from the search bar in the [Straddle Dashboard](https://dashboard.straddle.com) header. Type a partial name, email, amount, or description and results appear instantly, grouped by entity type. Press Cmd+K (Mac), Ctrl+K (Windows), or `/` to open search from anywhere in the dashboard. The **All** tab shows top matches. Open a type tab to page through just that type. Each row shows the date and context like amount and status, so you can confirm the right record before clicking through. Search handles typos, so "Swanosn" finds "Swanson." See the [dashboard walkthrough](https://help.straddle.com/article/how-to-use-search-in-the-dashboard) for tips on searching by entity type. Universal search results in the Straddle Dashboard, grouped into Charges, Payouts, Paykeys, Customers, Accounts, and Funding Events tabs **Upload proof of authorization via API** No more email threads. When a payment is held or a bank requests evidence, upload the authorization record straight to the payment with [`POST /v1/charges/{id}/authorization`](/guides/payments/statuses#provide-proof-of-authorization) or `POST /v1/payouts/{id}/authorization`. Send a PDF, PNG, JPG, DOC, or DOCX up to 10 MB. **Confirm receipt instantly** The charge and payout objects return the uploaded document, and the `charge` and `payout` webhooks include it, so you know it landed without polling. See the [Proof of Authorization guide](https://help.straddle.com/article/proof-of-authorization-poa-guide) for what makes a POA compliant. **Alerts and notifications widget** A new widget sits at the top of the [Straddle Dashboard](https://dashboard.straddle.com) and surfaces what needs your attention. Two tabs separate action-required *Alerts* from informational *Notifications*, and every row deep-links to the page where you can investigate or resolve. See the [dashboard walkthrough](https://help.straddle.com/article/how-to-use-the-alerts-and-notifications-widget-in-the-dashboard) for the full event catalog and what each tab looks like in practice. Alerts and notifications widget on the dashboard **Email notifications** The same events also land in your inbox. Add one or more [mailboxes](https://help.straddle.com/article/how-to-set-up-email-notifications-in-the-dashboard) (for example `ops@yourcompany.com`) on any account, and Straddle delivers email notifications there for charge failures, items under review, blocked paykeys, and completed charges, payouts, and funding events. No webhook handler required. Example email: a paykey flagged for review Refund a successfully paid [charge](https://straddle.dev/api-reference#tag/charge/POST/v1/charges/\{id}/refund) directly from the dashboard or API. Refunds return funds to the customer's original bank account and link back to the source charge via [`related_payments`](/guides/payments/statuses#refund-paid-charges) for clean reconciliation. Partial and full refunds are both supported; one refund per charge. See the [step-by-step dashboard walkthrough](https://help.straddle.com/article/how-to-refund-a-paid-charge-in-the-dashboard). Refund flow on the payment detail page **Get account settings via API** Programmatically retrieve the settings for any account using the new [GET /v1/account\_settings/\{account\_id}](https://docs.straddle.com/api-reference/accounts/account-settings) endpoint. Pull configuration details directly into your own tools and dashboards without manual lookups. **Resubmit endpoints in the API reference** Dedicated API reference pages are now live for resubmitting [charges](https://docs.straddle.com/api-reference/charges/resubmit) and [payouts](https://docs.straddle.com/api-reference/payouts/resubmit), making it easier to integrate retry logic for failed, reversed, or cancelled payments while preserving the original bank and payment details. You can now quickly [resubmit](/guides/payments/statuses#resubmit-failed-payments) failed, reversed, or cancelled [charges](https://straddle.dev/api-reference#tag/charge/POST/v1/charges/\{id}/resubmit) or [payouts](https://straddle.dev/api-reference#tag/payout/POST/v1/payouts/\{id}/resubmit) while automatically preserving their original bank and payment details. **Self-Service Capabilities and Limit Management** Account holders can now view, configure, and request changes to their payment capabilities and transaction limits directly from the dashboard or via API request, no support ticket required. Capability Request Page **Request Limit Increases** From the Capabilities tab on an [Account](https://dashboard.straddle.com/accounts) page or [Company Profile](https://dashboard.straddle.com/company-profile), you can now request changes to account limits. Adjustable fields include `max_amount`, `daily_amount`, `monthly_amount`, and `monthly_count`. Submitted requests enter a compliance review workflow, and you'll be notified once a decision is made. **Enable New Capabilities** Request activation of additional payment types, customer types, and consent types from the same capabilities tab. You can also configure signed agreement settings to require formal contracts for high-value transactions. **API Support** Use the [POST /v1/accounts/capability\_requests](https://docs.straddle.com/api-reference/capabilityrequests/create) endpoint to programmatically request capability changes. **Funding Event CSV Export** You can now export a full breakdown of any funding event directly from the [dashboard](https://dashboard.straddle.com/funding). Request a CSV from the funding event details page and receive an itemized report in your inbox. Screenshot2026 03 18at11 27 33AM **Unified Login** Access all your organizations with a single login. Seamlessly switch between them to streamline your payment operations without the hassle of managing multiple credentials. Org Switcher **User Invites for Platforms** Platform admins can now invite users to organizations directly, no support ticket required. Just head to the [Accounts](https://dashboard.straddle.com/accounts) tab, select an account, and send an invite from the Users tab. User Invite **Introducing Straddle Ledger** Meet the Straddle Ledger: a centralized, double-entry system built for modern finance. Get real-time visibility into every charge, payout, return, and exception with faster fund access, same-day payout capabilities, and clearer bank statements. Every state change, tracked. Every dollar, accounted for. **Faster Liquidity** The Straddle Ledger uses the earliest processing windows to speed up funding timelines. If using same-day ACH windows, charges post to the customer's account the same day which speeds up your funding by a day. **Efficient Payouts** Payouts now qualify for same-day funding when submitted by the [first same-day ACH window](https://help.straddle.com/article/same-day-ach-vs-standard-ach-cut-off-times#ach-cut-off-times). To take advantage of this, ensure your account is enabled for 'immediate' funding or contact [compliance@straddle.com](mailto:compliance@straddle.com) to request this capability. **Clearer Bank Statements** [Payment descriptions](https://docs.straddle.com/guides/payments/charges#param-description) now appear on bank statements with up to 80 characters of detail helping customers recognize charges at a glance. **Real-Time Funding Visibility** Know the moment your money moves. Funding event webhooks fire as soon as status changes and you see updates immediately in the dashboard. **Under the Hood** The Straddle Ledger is built for zero double-spends, always-correct balances, and real-time balance limits enforced at the ledger level. It's multi-cloud with self-healing failover, 6 replicas for consensus, and an immutable audit trail baked in from day one. **What’s Next** This architecture is the foundation for stored value wallets, multi-currency (including crypto), infinite accounts, and direct-to-rail payments. This is just the beginning. **Recover Blocked Paykeys Instantly** When a paykey is blocked (e.g. R29), your customer can't pay or get paid until it's fixed. Unblock in the dashboard once they've updated their bank settings so they can use the paykey again quickly. Note that you can only unblock a paykey once. View blocked paykeys in the [Overview](https://dashboard.straddle.com/) tab or manage them directly from the specific [Customer](https://dashboard.straddle.com/customers) page. Paykey Unblocking **API Support for Unblocking** Use the new [PATCH /v1/paykeys/id/unblock](https://straddle.dev/api-reference#tag/paykeys/PATCH/v1/paykeys/\{id}/unblock) endpoint to programmatically unblock eligible paykeys. **Handling R29 Returns** Corporate "positive pay" blocks often cause R29 returns; you can now confirm the customer has added your ACH identifier to their approved list and click Unblock Paykey in the dashboard. # Install the Straddle plugin Source: https://docs.straddle.com/developer-tools/agent-plugin/install Add Straddle skills, Docs MCP, and API MCP to Claude Code, Codex, or Cursor. Install the Straddle plugin to help your agent plan, build, and test a Straddle integration. The plugin includes Straddle skills and connections to the hosted Docs MCP and API MCP servers. ## Before you start Prepare the following: * **Your coding client:** Claude Code or Codex with plugin commands available, or Cursor with team marketplace access. * **Node.js 22.18 or later:** Required for the Straddle Wizard commands on this page. * **A sandbox API key:** Get one from the [Straddle dashboard](https://dashboard.straddle.com) to use the API MCP. Docs MCP needs no key. For Claude Code and Codex, set `STRADDLE_API_KEY` through your secret manager or shell environment before starting the client. Desktop apps must inherit the variable in their own process. Cursor's plugin has a field for the key in **Configure**. ## Install for your client Choose your client and complete its steps. The Straddle Wizard downloads a released plugin, verifies its checksum, and registers it with Claude Code or Codex. Cursor installs through its team marketplace. From your project directory, run the installer and confirm its download and installation prompts: ```bash theme={null} npx @straddlecom/wizard@latest install --client claude ``` The Wizard installs `straddle@straddle` in user scope, including both MCP server declarations. Check the installed plugin and the Wizard's verification result: ```bash theme={null} claude plugin list --json npx @straddlecom/wizard@latest status --json ``` Confirm that `straddle@straddle` is enabled. In the Wizard output, find the `claude` entry in `clients` and confirm `plugin.state` is `installed` and `plugin.verified` is `true`. Start a new Claude Code session, then enter `/mcp`. Confirm that the plugin's `straddle-api` and `straddle-docs` servers connect. From your project directory, run the installer and confirm its download and installation prompts: ```bash theme={null} npx @straddlecom/wizard@latest install --client codex ``` The Wizard installs `straddle@straddle` and configures API MCP to read its bearer token from `STRADDLE_API_KEY`. Check the plugin, MCP configuration, and Wizard verification result: ```bash theme={null} codex plugin list --json codex mcp list --json npx @straddlecom/wizard@latest status --json ``` Confirm that `straddle@straddle` is enabled and both `straddle-api` and `straddle-docs` appear. The API server's `bearer_token_env_var` must be `STRADDLE_API_KEY`. In the Wizard output, find the `codex` entry in `clients` and confirm `plugin.state` is `installed` and `plugin.verified` is `true`. Start a new Codex session to load the plugin. In the Cursor IDE, open **Add Marketplace**, then select **Import from GitHub**. Enter the repository URL, set **Scope** to **Team**, and select **Import**: ```text theme={null} https://github.com/straddle-build/skills ``` On Enterprise plans, a team administrator must add the marketplace. Cursor follows the repository's default branch when it refreshes the marketplace. Add **Straddle** from the imported marketplace. Open the plugin's **Configure** dialog and enter your sandbox API key in **Straddle API key** (`STRADDLE_API_KEY`). Confirm that Cursor lists `straddle-setup`, `straddle-plan`, `straddle-integrate`, and `straddle-test`, along with the plugin's `straddle-api` and `straddle-docs` MCP servers. Reload Cursor if the servers haven't appeared, then check that their tools load. ## Check the connection Ask your agent to use the API MCP's specification summary tool: Use straddle-api's summarize-openapi-specs tool to summarize the available Straddle API specification. Expect a summary of the API specification. This verifies the MCP connection and specification access. Setup checks API key configuration separately. API MCP connects to `https://mcp.scalar.com/mcp/d5d1b1c2-ae5b-432d-b795-4fcb31cfdedd`. Its `execute-request` tool runs Straddle API operations with your key, including writes. Keep your client's tool approval prompts enabled so you can review each request. ## Run Setup In your project directory, select the sandbox environment and start the Straddle Wizard's Setup workflow: ```bash theme={null} export STRADDLE_ENVIRONMENT=sandbox npx @straddlecom/wizard@latest setup ``` Select your client and **Auto** to run the workflow in your terminal, or **Manual** for a prompt to paste into your agent. Setup checks your project, CLI, SDK, environment, and MCP connections, then writes `straddle-setup.md` with the results and next actions. ## Install skills in another client For a client supported by the skills installer, install the skills and choose your client when prompted: ```bash theme={null} npx skills add straddle-build/skills ``` This route copies the skills into your client. Add MCP connections separately using [Connect MCP](/developer-tools/mcp/install). ## Update or remove the plugin For a Wizard-managed installation, use the matching client name. For example, update Claude Code's plugin: ```bash theme={null} npx @straddlecom/wizard@latest update --client claude ``` Replace `claude` with `codex` for Codex. Restart your client, then repeat its verification steps. To remove the plugin and its marketplace, run: ```bash theme={null} npx @straddlecom/wizard@latest remove --client claude ``` For Codex, use `--client codex`. To also remove the client-level Straddle MCP entries, run `npx @straddlecom/wizard@latest mcp remove --client codex`. In Cursor, refresh the team marketplace to update, or enable **Auto Refresh**. To remove the installation, uninstall **Straddle**, then remove the marketplace if your team no longer uses it. # Use the CLI with coding agents Source: https://docs.straddle.com/developer-tools/cli/agent-use Discover commands, inspect context, preview requests, and consume machine-readable results. Give your agent the installed CLI and [configured credentials and context](/developer-tools/cli/auth-context). Use runtime discovery to plan each task against the commands that version supports. ## Discover and inspect a command Read the command description and find a payment workflow: ```bash theme={null} straddle agent-context --pretty straddle which "reconcile funding" --json straddle reconcile --help ``` `agent-context` includes `schema_version`, command names and flags, authentication requirements, and `runtime_context`. It reports the selected environment and account without opening the local store. `which` searches the built-in workflow descriptions; use resource help, such as `straddle charges --help`, for API operations. ## Choose an output mode Choose the following mode for your caller: | Caller | Option | Behavior | | - | - | - | | Terminal user | Default | Readable resource tables or detail output. | | Terminal user who wants rich formatting | `--human-friendly` | Enables rich terminal formatting and color. | | Script that needs JSON | `--json` | Selects JSON without changing confirmation defaults. | | Coding agent | `--agent` | Defaults to `--json --compact --no-input --no-color --yes`. | Piped or redirected resource output uses JSON unless another supported output format is selected. Piping doesn't enable the other `--agent` defaults. `--human-friendly` keeps piped resource output in JSON. Explicit flags override agent defaults. To keep full resource fields, use `--agent --compact=false`. To request a smaller set of fields: ```bash theme={null} straddle payments --agent --select id,status,amount ``` `--select` applies to resource fields, not envelope paths such as `meta.source`. Streaming commands have their own output shape: `sync`, for example, emits one JSON event per line. ## Preview a request before sending it Before a write, check the effective environment and acting account with `agent-context`, inspect the operation's help, and prepare the request body. For a charge body saved as `charge.json`: ```bash theme={null} straddle charges create --help straddle charges create --stdin --dry-run --agent < charge.json ``` The dry run validates required inputs and prints the request preview to stderr without sending it. Review the method, URL, account header, and body. This preview verifies request construction; the API validates permissions and payment conditions when you send the request. `--agent` includes `--yes`, so commands that require confirmation can proceed without another prompt. Obtain approval for the exact write before removing `--dry-run`. ## Read fresh results and handle errors For a fresh API result, bypass both local fallback and the HTTP response cache: ```bash theme={null} straddle payments --page-size 10 --data-source live --no-cache --agent ``` List commands return one page by default. Add `--all` when the task requires every page. On reads that include provenance, inspect `meta.source` and `meta.synced_at` to distinguish API results from local data. Capture stdout, stderr, and the process exit code separately. A failed command can report diagnostics as text on stderr even with `--agent`. Follow the [error recovery guide](/developer-tools/cli/troubleshooting#respond-to-an-error) before retrying a write. Use `straddle api` to discover the raw interfaces. If you have a verified endpoint path, preview it with the shared credentials and account rules: ```bash theme={null} straddle api get /v1/customers --param page_size=1 --dry-run --agent ``` After reviewing the preview, remove `--dry-run` to send the read. Add `--no-cache` when it must reach the API. # Configure credentials and account context Source: https://docs.straddle.com/developer-tools/cli/auth-context Select an API key, environment, integration type, and acting account before your first API read. Connect the [installed CLI](/developer-tools/cli/install) to the environment and account you want to work with. Start with a sandbox API key from the [Straddle dashboard](https://dashboard.straddle.com). Choose how the CLI receives your key: Set `STRADDLE_API_KEY` in your shell or through your secret manager. Replace the placeholder locally: ```bash theme={null} export STRADDLE_API_KEY="YOUR_SANDBOX_API_KEY" ``` This variable overrides a token saved with `auth set-token`. Enter keys outside agent prompts and shared scripts; shell history can retain commands that contain them. Save the key in the CLI's owner-only configuration file: ```bash theme={null} straddle auth set-token YOUR_SANDBOX_API_KEY ``` The default file is `~/.config/straddle/config.toml`. The command contains the key, so account for shell history when entering it. Inspect credential presence and source: ```bash theme={null} straddle auth status --json ``` `authenticated: true` means a credential is present. `verified: false` means this check hasn't tested it against the API. Use sandbox while building and testing: ```bash theme={null} export STRADDLE_ENVIRONMENT=sandbox ``` Sandbox is the default. Use `production` with a production key when you're ready for production operations. A configured `STRADDLE_BASE_URL` or `base_url` can override the standard host, so verify the resolved environment in step 4. Choose the command that matches who owns the customers and payments: | Integration | Command | Ownership | | - | - | - | | Direct business | `straddle setup --type account` | One business collects or sends its own payments. | | SaaS platform | `straddle setup --type saas` | Your clients own their customers. | | Marketplace | `straddle setup --type marketplace` | Your platform owns the customers. | For a SaaS or marketplace platform, select the embedded account for account-level work: ```bash theme={null} straddle use-account ACCOUNT_ID ``` This selection stays in effect until changed. `straddle use-account --clear` returns to a context without an acting account. Direct business integrations use their key's account and omit this step. Inspect `runtime_context.environment`, `integration_type`, and `acting_account`: ```bash theme={null} straddle agent-context --pretty ``` Then request one customer from the selected environment: ```bash theme={null} straddle customers list --page-size 1 --data-source live --no-cache --json ``` A successful response, including an empty list, confirms that the key can perform this operation. Resolve any [authentication or scope error](/developer-tools/cli/troubleshooting) before continuing. ## Choose an account for one command For a platform payment read, override the saved account with `--account`: ```bash theme={null} straddle payments --account ACCOUNT_ID --data-source live --no-cache --json ``` The CLI applies `Straddle-Account-Id` by operation and integration type. Marketplace customer, paykey, and Bridge operations use platform ownership. Account-management operations take IDs in the path or body. See [account scoping](/developer-tools/mcp/account-scoping) for the ownership rules. Credentials live in `config.toml`; integration type and the saved account live in `platform.toml`. `STRADDLE_CONFIG` selects the credentials file and places `platform.toml` beside it. `STRADDLE_PLATFORM_CONFIG` selects the platform file explicitly. The `--config` flag changes only the credentials file. A profile applies saved flag values to one invocation. Inspect it with `straddle profile show PROFILE_NAME`, then use `--profile PROFILE_NAME` on compatible commands. `profile use` prints values; it doesn't activate a persistent profile. Explicit flags override saved values. A saved `account` acts as an explicit `--account`, including on commands that reject it. Run `use-account` and profile inspection without `--profile`. Profiles can also supply sync filters or `path-context`; review [sync completeness](/developer-tools/cli/local-data#check-sync-completeness) before using them for analysis. # Install the Straddle CLI Source: https://docs.straddle.com/developer-tools/cli/install Install the CLI on macOS, Linux, or Windows and verify the command is available. Install `straddle` with a package manager or a release archive. Release binaries support x64 and ARM64 on macOS, Linux, and Windows. On macOS, install from the Straddle tap: ```bash theme={null} brew install straddle-build/tap/straddle ``` With Node.js 18 or later, install the CLI globally: ```bash theme={null} npm install -g @straddlecom/cli ``` To try it without a global installation, run `npx @straddlecom/cli --help`. Keep npm's optional dependencies enabled; they provide the binary for your platform. On macOS or Linux, use the shell installer: ```bash theme={null} curl -fsSL https://raw.githubusercontent.com/straddle-build/straddle-cli/main/install.sh | sh ``` The installer downloads a release, verifies its SHA-256 checksum, and installs to `~/.local/bin`. Set `STRADDLE_INSTALL_DIR` for the installer process to choose another directory. Download the archive for your operating system and architecture from [Straddle CLI releases](https://github.com/straddle-build/straddle-cli/releases). Compare its SHA-256 checksum with the release's `checksums.txt`, then extract the binary into a directory on `PATH`. macOS release binaries are signed and notarized. Gatekeeper needs a network connection to check notarization on the first launch of a quarantined download. Check the version and available commands: ```bash theme={null} straddle version straddle --help ``` A version number and command list confirm that your shell can run the CLI. If the command isn't found, add the installation directory to `PATH` and open a new terminal. [Configure credentials and context](/developer-tools/cli/auth-context), then make a read request to confirm the API key works in the selected environment. With a Go toolchain that meets the release's [module requirements](https://github.com/straddle-build/straddle-cli/blob/v1.0.4/go.mod), install from source: ```bash theme={null} go install github.com/straddle-build/straddle-cli/cmd/straddle@latest ``` Add your Go binary installation directory to `PATH`, then run `straddle version`. # Synchronize and query local data Source: https://docs.straddle.com/developer-tools/cli/local-data Prepare a scoped SQLite store for search, SQL, reconciliation, and payment analysis. Synchronize Straddle resources to answer questions across payments, customers, paykeys, and funding events. The CLI stores the data in SQLite at `~/.local/share/straddle/data.db` by default. ## Prepare the data for analysis With [credentials and account context configured](/developer-tools/cli/auth-context), inspect the context and fetch the resources needed for payment analysis: ```bash theme={null} straddle agent-context --pretty straddle sync --resources payments,funding-events --full --max-pages 0 --strict --json ``` `--full` restarts from the beginning instead of a saved checkpoint. `--max-pages 0` removes the default cap of 100 pages per resource. Sync bypasses the HTTP response cache and adds or updates returned records. It retains previously synchronized records that are absent from later API lists, including during a full sync. For an interrupted sync, rerun with the same context and resources without `--full` to use its saved progress. Before an investigation that needs refreshed historical records, run the full command again. ## Check sync completeness Read the JSON event stream and the `sync_summary` fields `success`, `warned`, and `errored`. Check each resource you need, including dependent resources added by sync. Naming a parent resource also synchronizes its parent-keyed dependents. The following results need attention before you treat the data as complete: | Result | Action | | - | - | | `sync_warning` for denied access | Confirm the key and account can read that resource. | | `sync_warning` with `max_pages_cap_hit` | Repeat with `--max-pages 0` or a deliberate narrower scope. | | `sync_anomaly` | Inspect malformed or dropped records, resolve the reported cause, and synchronize again. | | A resource error | Resolve the error and rerun that resource. | | A required resource missing from the run | Add it to `--resources` and synchronize again. | `--strict` makes per-resource errors fail the command. Access warnings remain warnings, so a zero exit code alone doesn't prove complete coverage. Query filters still apply during a full sync. `--param`, `--resource-param`, and `--global-param` can narrow the fetched data. `--latest-only` limits a resource to its first page when `--since` is absent, even with `--full --max-pages 0`. In CLI v1.0.4, `--since` produces a `resource_not_incremental` warning for every supported sync resource and sends the request without a date filter. For a date-limited sync, use a query parameter supported by that resource's API operation. The command shown here uses no saved profile. If you add `--profile`, inspect it first with `straddle profile show PROFILE_NAME`. Saved filters and `latest-only` still apply. A saved `path-context` can change the environment used by sync without changing the context of later queries. ## Query the local store Search the synchronized data or run a read-only query: ```bash theme={null} straddle search "failed" --type payments --data-source local --json straddle sql "SELECT id FROM payments LIMIT 20" --json ``` `search` uses SQLite full-text search. For live filtered searches, use the resource command, such as `straddle payments --help`. SQL accepts one `SELECT` or `WITH` statement and runs against a read-only snapshot of the current context. Resource JSON is available in each table's `data` column. If you sync to a custom `--db` path, pass that path to `search`, `sql`, and analytics commands that read it. Generated API read commands use the default store for local fallback. ## Keep the same environment and account Local rows are separated by the resolved API origin and acting account. A context without an acting account has its own rows; it isn't an all-account view. Direct business integrations use no acting account. Keep the environment and account selection the same for sync and analysis. Different profiles can share rows when they resolve to the same environment and account. Integration type controls request headers and account selection, rather than adding a separate database partition. For a marketplace, customers and paykeys remain platform-owned. Sync fetches them without an account header, then stores them under the selected acting account's local context. That local grouping doesn't make those customers or paykeys account-owned. Records written by versions before scoped storage remain hidden from scoped reads. A nonzero `hidden_legacy_records` count in diagnostics or read metadata means you need to resync the intended context. ## Choose between API, local data, and the response cache Read commands that support both sources accept the following options: | Option | Read behavior | | - | - | | `--data-source auto` | Try the API, update the local store after a successful supported read, and fall back locally for network failures. | | `--data-source live` | Use the API path, with no local fallback. | | `--data-source local` | Read synchronized data in the current context. | The HTTP response cache is separate from SQLite and can reuse GET responses for five minutes. `--data-source live --no-cache` requests a fresh API result. `--no-cache` leaves your SQLite data intact. Commands such as `reconcile` and `sql` always read local data. Use the synchronized store for reconciliation, payment progress, returns, and charge and payout volume. # Work with Straddle from your terminal Source: https://docs.straddle.com/developer-tools/cli/overview Read API resources, automate tasks, and investigate synchronized payment data with the Straddle CLI. Use the Straddle CLI to inspect payments, call the Pay by Bank and Embed APIs, and answer questions from a local copy of your data. Install the CLI, configure your API key and account context, and verify an API read. ## Find the command for your task Discover payment workflows and inspect their options: ```bash theme={null} straddle which "reconcile funding" --json straddle reconcile --help ``` For API operations, inspect the resource's commands with `straddle customers --help`. Coding agents can read the full command description from `straddle agent-context`. ## Choose how to work Select sandbox or production, your integration type, and an acting account. Discover commands, preview requests, and consume JSON output. Prepare a local SQLite store for search, SQL, and payment analysis. Follow a playbook for payment progress, reconciliation, returns, or charge and payout volume. In a terminal, resource commands show readable output. Add `--agent` for compact JSON and automation defaults, or `--json` for JSON without changing confirmation behavior. See [output modes](/developer-tools/cli/agent-use#choose-an-output-mode). # Troubleshoot the Straddle CLI Source: https://docs.straddle.com/developer-tools/cli/troubleshooting Resolve installation, credentials, account context, incomplete data, and automation errors. Start with the version, credential source, and effective context: ```bash theme={null} straddle version straddle auth status --json straddle agent-context --pretty ``` For connectivity and local-store diagnostics, run `straddle doctor --json`. Doctor makes a reachability request to the configured API host. Its credential-presence result needs a successful resource read to confirm authorization. ## The shell can't find the command Add the installation directory to `PATH` and open a new terminal. The shell installer uses `~/.local/bin` by default. For npm, confirm the global binary directory is on `PATH` and optional dependencies were installed. See [installation methods](/developer-tools/cli/install). ## The API key is rejected Check `auth status` for the credential source. An exported `STRADDLE_API_KEY` overrides a token saved with `auth set-token`. Pair a sandbox key with sandbox and a production key with production. Inspect `runtime_context.environment` in `agent-context`. If it differs from `STRADDLE_ENVIRONMENT`, check `STRADDLE_BASE_URL` and the configuration file's `base_url`. After correcting the configuration, verify a fresh read: ```bash theme={null} straddle customers list --page-size 1 --data-source live --no-cache --json ``` ## An account-scoped command is rejected Inspect the saved integration type and account: ```bash theme={null} straddle setup straddle use-account ``` For a platform's account-level work, select the intended account with `straddle use-account ACCOUNT_ID`. Direct business integrations use `setup --type account` and omit `--account`. An explicit `--account` is rejected on operations that don't accept the account header. A profile can supply that flag too. Inspect the profile without applying it: `straddle profile show PROFILE_NAME`. See [account context](/developer-tools/cli/auth-context) for the setup path. ## Local results are missing or older than expected Confirm that sync and the query use the same API environment, acting account, and database path. An empty acting account selects its own data, rather than every account. Inspect the last sync's resource events and `sync_summary`. Access warnings, filters, or a page cap can leave the data incomplete even when sync exits successfully. Follow [sync completeness checks](/developer-tools/cli/local-data#check-sync-completeness), then rerun the resources needed for your task. If diagnostics report `hidden_legacy_records`, resync in the intended context. For a fresh API read instead of local analysis, use `--data-source live --no-cache`. ## An agent receives unexpected output Use `--agent` for compact JSON or `--json` for full JSON output. Add `--compact=false` to agent mode when you need fields omitted by compact output. Resource output remains JSON when piped, including with `--human-friendly`. Parse `sync` as newline-delimited JSON events, not a single object. Keep stderr separate from stdout; errors and request previews can appear there as text. See [agent output modes](/developer-tools/cli/agent-use#choose-an-output-mode). ## Respond to an error Use the exit code and diagnostics to choose the next action: | Exit code | Meaning | Next action | | - | - | - | | `1` | General command failure | Read stderr and any resource-level events. | | `2` | Invalid command or arguments | Check the command's `--help` and correct inputs. | | `3` | Resource not found | Check its ID, environment, and account. | | `4` | Authentication or permission error | Check the key's source, environment, and permitted resources. | | `5` | API error | Read the status and response details; resolve the reported condition. | | `6` | Partial failure detected in a response | Inspect the reported successful and failed operations before retrying. | | `7` | Rate limited | Wait before retrying and reduce request frequency. | | `10` | Configuration error | Correct the reported configuration file or environment variable. | A timeout during a write can leave the result uncertain. Check the resource's current state before retrying. For a request that supports an idempotency key, retain the same key when retrying the same operation. # Set account scope Source: https://docs.straddle.com/developer-tools/mcp/account-scoping Choose when to send Straddle-Account-Id for direct, SaaS, and marketplace requests. Set account scope for each API MCP request. The `Straddle-Account-Id` header names the embedded account a platform acts for; whether to send it depends on your integration model and the operation. Set the account in your MCP request separately from the account selected in the Straddle CLI. ## Choose the account For a platform request, use the Straddle account ID from your application's tenant mapping or an exact account lookup. Resolve an ambiguous match before continuing. For the account model itself, see [Manage embedded accounts](/guides/embed/accounts). Keep the following facts together when reviewing a request: | Fact | Example | | - | - | | Environment | Sandbox, `https://sandbox.straddle.com` | | Integration model | SaaS | | Selected account | The sandbox account ID you supplied | | Operation | `GET /v1/charges/{id}` | | Header | `Straddle-Account-Id` set to that account ID | Confirm the integration model in your platform configuration and integration plan. ## Apply the header rule Use the following rules for the request you discovered: | Operation | Direct account | SaaS | Marketplace | | - | - | - | - | | Create customer, create paykey through Bridge, initialize Bridge | Omit | Required | Omit | | Other customer and paykey reads and updates | Omit | Send when an account is selected | Omit | | Create charge or payout, refund, resubmit, upload charge authorization | Omit | Required | Required | | Other charge, payout, funding-event, and payment reads and updates | Omit | Send when an account is selected | Send when an account is selected | | Organizations, accounts, account settings, representatives, linked bank accounts, onboarding | Omit | Omit | Omit | When a SaaS or marketplace row says “send when an account is selected,” omit the header if no account is selected. Select the account explicitly for a task about one tenant. Marketplace customers and paykeys belong to the platform, so their requests omit the header. Charges and payouts identify the seller's account when the operation requires it. ## Pass scope to API MCP For an account-scoped request, include the selected ID in `execute-request`'s `headers`. Replace the placeholder with the account you confirmed: ```json theme={null} { "Straddle-Account-Id": "" } ``` For account-management operations such as `GET /v1/accounts/{account_id}`, the path identifies the account and the header stays omitted. ## Switch to another account Confirm the new account ID, review the operation's header rule, and rebuild the request before sending it. Any write preview must show the new target before you approve it. For a first authenticated read, follow [Read an account through API MCP](/developer-tools/mcp/api-requests). # Read an account through API MCP Source: https://docs.straddle.com/developer-tools/mcp/api-requests Discover a current operation and inspect one sandbox account with your coding agent. Use API MCP to read an existing sandbox account and verify that your configured key can reach it. The workflow discovers the operation, reviews the request, and inspects the result. ## Before you start Prepare the following: * [Connect API MCP](/developer-tools/mcp/install) with a sandbox API key. * Choose an existing sandbox account ID that your key can read. * Confirm the request host is `https://sandbox.straddle.com`. The account ID goes in the request path. Account-management requests omit `Straddle-Account-Id` for every integration model. ## Discover and run the read Ask the agent to discover the account read and show you its inputs: Use straddle-api's search-openapi-operations to find the operation that gets one account by ID. Read its current schema and capture the Scalar document-version and operation IDs from this result. Ask me for the sandbox account ID, then show the proposed GET request to [https://sandbox.straddle.com](https://sandbox.straddle.com) with Straddle-Account-Id omitted. Wait for me to confirm the read. Discovery returns the operation's schema for your review before execution. Check the proposed values: | Input | Expected value | | - | - | | `method` | `GET` | | `serverBaseUrl` | `https://sandbox.straddle.com` | | `path` | `/v1/accounts/` followed by your chosen account ID | | `xScalarDocumentId` | The discovered `x-scalar-document-version-id`. | | `xScalarOperationId` | The discovered operation's `x-scalar-operation-id`. | | Account header | Omitted. | Your client supplies the bearer token. Keep the key out of the prompt and tool arguments. Confirm the proposed request and let the agent call `execute-request` once. Review the client's tool approval prompt if it appears. Ask the agent to report the HTTP status, returned account ID, account status, and request ID when available. Keep personal and business details out of the summary unless your task needs them. A successful response verifies access to that sandbox account with the configured key. Confirm the returned account ID matches the one you selected. For a failed response, keep the status and request ID and follow [MCP troubleshooting](/developer-tools/mcp/troubleshooting). ## Use current Scalar IDs Take both IDs from `search-openapi-operations` in the same session. Contract publication can change them. The OpenAPI `operationId`, such as `getAccount`, is a human-readable name. `execute-request` needs the Scalar UUID from `x-scalar-operation-id`. ## Adapt the workflow For another read, discover that operation's schema and review its parameters first. Put query parameters in `path`, for example `/v1/accounts?page_size=1`. Apply the [account-scope rules](/developer-tools/mcp/account-scoping) for the resource and integration model. For implementation and sandbox writes, use the [Straddle skills](/developer-tools/skills/use-kit). They prepare request previews and choose the SDK, CLI, or API MCP route for each operation. [Authentication and permissions](/developer-tools/mcp/safety) explains those choices. # Search Straddle documentation Source: https://docs.straddle.com/developer-tools/mcp/docs-search Get source-backed integration guidance from your coding agent with Docs MCP. Use Docs MCP to find Straddle guides and API reference material while you work in your coding agent. Documentation search needs no API key. ## Connect Docs MCP [Install the Straddle plugin](/developer-tools/agent-plugin/install), or add only `straddle-docs` with the [direct connection instructions](/developer-tools/mcp/install). The server address is: ```text theme={null} https://straddle-build-straddle-openapi.apidocumentation.com/mcp ``` ## Ask a focused question Include the resource, integration model, and behavior you need to understand. Ask the agent to cite the documentation it used. Use straddle-docs to find the account-scope rules for a SaaS integration. Explain when customer, paykey, and charge requests use Straddle-Account-Id. Link to the source pages. The agent uses `search-documentation` with your question. A useful answer names the applicable rule and provides a source you can open. ## Apply the result Open the linked guide or API reference. Confirm that it covers your integration model and the operation you plan to use. For a code change, have the agent read your installed SDK's methods and models before writing the implementation. Documentation explains the flow; the installed package determines the code available in your project. Run your application tests and the sandbox scenarios in your integration plan. Use [Straddle Test](/developer-tools/skills/catalog) to record the results. ## Ask about an error Give the agent the error code and relevant operation, with secrets and personal data removed: Use straddle-docs to find guidance for a 401 response from GET /v1/accounts in sandbox. Explain which client and environment settings to check, and cite the documentation. To inspect a resource in your Straddle account, use [API MCP](/developer-tools/mcp/api-requests). ## Read documentation without MCP Give your agent the [documentation index](https://straddle-build-straddle-openapi.apidocumentation.com/llms.txt) to find pages directly. This is also useful when your client has no MCP support. # Connect MCP Source: https://docs.straddle.com/developer-tools/mcp/install Add the hosted Straddle Docs MCP and API MCP servers to your coding agent. Connect Docs MCP for documentation search and API MCP for Straddle requests. If you want integration skills too, [install the Straddle plugin](/developer-tools/agent-plugin/install), which includes both connections. ## Before you start Use a client that supports remote HTTP MCP servers. For API requests, get a sandbox API key from the [Straddle dashboard](https://dashboard.straddle.com) and supply it as `STRADDLE_API_KEY` in the environment that starts your client. Restart the client after setting the variable. A desktop app must inherit the variable in its own process, including when you open it outside a terminal. Docs MCP needs no credential, so you can connect it independently. ## Add the servers Choose your client. For documentation search alone, add only the `straddle-docs` entry or command. From your project directory, register both servers in local scope: ```bash theme={null} claude mcp add --transport http --scope local \ straddle-docs \ https://straddle-build-straddle-openapi.apidocumentation.com/mcp claude mcp add --transport http --scope local \ straddle-api \ https://mcp.scalar.com/mcp/d5d1b1c2-ae5b-432d-b795-4fcb31cfdedd \ --header 'Authorization: Bearer ${STRADDLE_API_KEY}' ``` Keep the single quotes around the header so Claude Code receives the variable reference. Start Claude Code from that environment, enter `/mcp`, and confirm both connections. Register the hosted servers: ```bash theme={null} codex mcp add straddle-docs \ --url https://straddle-build-straddle-openapi.apidocumentation.com/mcp codex mcp add straddle-api \ --url https://mcp.scalar.com/mcp/d5d1b1c2-ae5b-432d-b795-4fcb31cfdedd \ --bearer-token-env-var STRADDLE_API_KEY ``` Check the configuration before starting a new session: ```bash theme={null} codex mcp list --json ``` Confirm both server URLs and `bearer_token_env_var: "STRADDLE_API_KEY"` for `straddle-api`. Open `~/.cursor/mcp.json` for a personal connection, or `.cursor/mcp.json` for a project connection. Merge these entries into the existing `mcpServers` object: ```json theme={null} { "mcpServers": { "straddle-docs": { "url": "https://straddle-build-straddle-openapi.apidocumentation.com/mcp" }, "straddle-api": { "url": "https://mcp.scalar.com/mcp/d5d1b1c2-ae5b-432d-b795-4fcb31cfdedd", "headers": { "Authorization": "Bearer ${env:STRADDLE_API_KEY}" } } } } ``` In **Customize**, confirm both servers are enabled and their tools appear. For additional options, see [Cursor's MCP guide](https://cursor.com/docs/mcp). In the Command Palette, select **MCP: Open User Configuration**. For a project connection, open `.vscode/mcp.json`. Merge these entries into the existing `servers` object: ```json theme={null} { "servers": { "straddle-docs": { "type": "http", "url": "https://straddle-build-straddle-openapi.apidocumentation.com/mcp" }, "straddle-api": { "type": "http", "url": "https://mcp.scalar.com/mcp/d5d1b1c2-ae5b-432d-b795-4fcb31cfdedd", "headers": { "Authorization": "Bearer ${env:STRADDLE_API_KEY}" } } } } ``` Select **MCP: List Servers**, select each server, and then select **Start**. Review the server trust prompt. In chat, open **Configure Tools** and confirm the tools appear. ## Verify each connection Ask your agent to query Docs MCP: Use straddle-docs to search for webhook signature verification. Summarize the relevant instructions and link to the source. Expect a relevant documentation result with a source link. Ask for a specification summary: Use straddle-api's summarize-openapi-specs tool to summarize the available Straddle API specification. Expect a specification summary. This checks discovery; [read a sandbox account](/developer-tools/mcp/api-requests) to verify an authenticated request. For connection or authentication errors, follow [MCP troubleshooting](/developer-tools/mcp/troubleshooting). # Connect your agent to Straddle Source: https://docs.straddle.com/developer-tools/mcp/overview Search Straddle documentation and work with the API through hosted MCP servers. Connect your coding agent to Straddle documentation and API tools with the Model Context Protocol (MCP). Straddle provides two hosted servers: Docs MCP for documentation search and API MCP for operation discovery and requests. ## Choose a connection Use the server that matches your task: | Server | Use it to | Authentication | | - | - | - | | Docs MCP, `straddle-docs` | Find guides, API reference material, and integration instructions. | No API key. | | API MCP, `straddle-api` | Discover operations and send requests to Straddle. | Your Straddle API key for requests. | The [Straddle plugin](/developer-tools/agent-plugin/install) connects both servers and adds integration skills. To configure MCP directly, follow [Connect MCP](/developer-tools/mcp/install). ## Work with the API API MCP exposes the following tools: | Tool | What it does | | - | - | | `summarize-openapi-specs` | Summarizes available specifications, servers, and paths. | | `search-openapi-operations` | Finds operations and their request schemas. | | `search-documentation` | Searches available documentation. | | `execute-request` | Sends an HTTP request for a discovered operation. | Specification discovery works separately from authenticated API execution. A successful summary proves the connection can read the contract. A successful API request proves access to that operation with the configured key. API MCP can run reads and writes permitted by your key. Choose the environment and account for each task, and review requests through your client's approval controls. See [Authentication and permissions](/developer-tools/mcp/safety). ## Start a task Add hosted servers to Claude Code, Codex, Cursor, or VS Code. Ask a focused question and get source-backed guidance. Discover the operation and inspect one sandbox account. Apply the right header for a direct, SaaS, or marketplace integration. # Authentication and permissions Source: https://docs.straddle.com/developer-tools/mcp/safety Understand API key access, client approvals, and the Straddle skills request rules. API MCP sends requests with your Straddle API key. The key's permissions determine which Straddle operations the server can execute; your client controls when it asks you to approve a tool request. ## Supply the API key Set `STRADDLE_API_KEY` in the environment that starts your client, or use the Straddle plugin's credential field in Cursor. Direct client configuration stores a reference to the variable. See [Connect MCP](/developer-tools/mcp/install) for the exact syntax. Use a key from the [Straddle dashboard](https://dashboard.straddle.com). API MCP uses that key as a bearer token and needs no Scalar login. Keep the key in the client environment or credential field, outside prompts, source files, and reports. A key saved in the Straddle CLI configures the CLI. Configure the MCP client's credential separately. ## Match the environment Choose the host explicitly in each API request: | Environment | `serverBaseUrl` | | - | - | | Sandbox | `https://sandbox.straddle.com` | | Production | `https://production.straddle.com` | Use a key for the same environment. Confirm the key's environment in the dashboard and the host in the request. ## Review API execution The API MCP's `execute-request` can perform reads, creates, updates, deletes, and sensitive-data operations permitted by the key. A production key can authorize production writes. Keep tool approval prompts enabled. Before approving execution, inspect the method, host, path, account header, and request body. For a write, check the intended effect and the idempotency key as well. ## Understand the skill rules The Straddle skills add instructions for integration work. These are workflow rules followed by the agent, separate from the server's API permissions: | Skill rule | What you review | | - | - | | Use sandbox for integration writes. | The explicit sandbox host and matching key. | | Preview a write before asking for approval. | Account, operation, payload summary, external ID, and idempotency key. | | Ask again when the target or payload changes. | The revised request. | | Route customer, paykey, charge, and payout creation through the SDK or CLI. | The generated code or CLI preview. | | Route deletes, unmasking, and paykey reveal through the SDK or CLI. | The specific approved action and handling of sensitive output. | The agent follows these routing instructions. The server still accepts any operation permitted by the supplied key. ## Interpret verification Documentation search and specification discovery can succeed without an authenticated Straddle request. Verify API access with a permitted read against the environment and account you intended. A successful read proves access to that operation and account. Follow [Read an account through API MCP](/developer-tools/mcp/api-requests) for a focused check. # Troubleshoot MCP Source: https://docs.straddle.com/developer-tools/mcp/troubleshooting Resolve connection, authentication, operation-discovery, and account-scope errors. Start with the failing step: connection, specification discovery, or the Straddle request. Each checks a different part of the setup. ## The server is missing or disconnected Check the server address in your client's MCP settings: | Server | Address | | - | - | | `straddle-docs` | `https://straddle-build-straddle-openapi.apidocumentation.com/mcp` | | `straddle-api` | `https://mcp.scalar.com/mcp/d5d1b1c2-ae5b-432d-b795-4fcb31cfdedd` | Use the [connection instructions](/developer-tools/mcp/install) for your client, then restart the connection. In Claude Code, inspect `/mcp`. In Codex, run `codex mcp list --json`. In Cursor, check **Customize**; in VS Code, use **MCP: List Servers**. If the URL is correct, inspect the client's MCP output for connection errors and confirm your network can reach that hosted address. ## Discovery succeeds but the request returns 401 Specification discovery checks the contract, so it can succeed without a valid API key. For a `401`, check the following: 1. Supply `STRADDLE_API_KEY` to the process that starts your client. 2. Confirm the key belongs to the same environment as `serverBaseUrl`. 3. Restart the client or MCP connection after changing the credential. For Codex, confirm `bearer_token_env_var` is `STRADDLE_API_KEY`. For Claude Code, the header must keep the literal variable reference shown in [Connect MCP](/developer-tools/mcp/install). For the Cursor plugin, check its **Configure** credential field. ## The request returns 403 or 404 For `403`, check whether the key can use the operation and selected account. For `404`, confirm the resource ID and environment, then review the [account header rule](/developer-tools/mcp/account-scoping). Use the resource's exact ID from the same environment. Keep the method, path, HTTP status, and request ID from the failure so the next investigation has concrete evidence. ## Scalar cannot find the operation “Failed to get operation” points to the operation ID. “Does not belong to the given document version” points to the document and operation pair. Repeat `search-openapi-operations` in the current session. Use `x-scalar-document-version-id` and the matching operation's `x-scalar-operation-id` from that result. The OpenAPI name, such as `getAccount`, is not the Scalar operation ID. Then rebuild the request with those IDs. See [API requests](/developer-tools/mcp/api-requests). ## The request targets the wrong environment Inspect `serverBaseUrl` in the tool request. Set it to the resolved host, such as `https://sandbox.straddle.com`. Set the account in the MCP request separately from the CLI's selected account. Include the header when the [operation requires it](/developer-tools/mcp/account-scoping). ## Docs MCP lists API execution tools Use Docs MCP's `search-documentation` tool for documentation. Send API tasks through `straddle-api`, where the client is configured with your Straddle key. The hosted server controls its tool list. Check the server URL to confirm which connection supplied the tools. ## Prepare an error report Include the client version, server name, tool name, method and path, environment, HTTP status, and request ID when available. Describe what you expected and what happened. Remove API keys, paykey tokens, and personal data before sharing the report. # Build your Straddle integration with AI Source: https://docs.straddle.com/developer-tools/overview Plan, build, and test with Claude Code, Codex, or Cursor. Straddle skills guide your coding agent from project setup through sandbox testing and production readiness. Start a guided integration with the Wizard, or choose a skill for the task you're working on. ## Start an integration Run the Straddle Wizard from your application directory to start the integration workflow: ```bash theme={null} npx @straddlecom/wizard@latest ``` Choose your coding agent and follow the workflow through setup, planning, implementation, sandbox testing, and a production readiness review. Set up your coding agent, approve an integration plan, and review the sandbox test results. ## Work in your coding agent The Straddle plugin adds skills and connections to Straddle's Model Context Protocol (MCP) servers. Use skills to guide a development task and MCP to search documentation or send API requests. Plan an integration, build a payment flow, test in sandbox, or audit existing code in your agent session. Search guides and API reference pages with Docs MCP. Use API MCP to discover operations and send requests with your Straddle API key. API MCP supports the operations your API key permits, including writes. Review each request in your agent's tool approval prompt before it runs. ## Investigate payments Playbooks walk you through an operational task and explain the results. Choose a workflow to inspect payment progress, investigate returns, or compare payment records with funding events. Find the workflow for your question, run it with the CLI, and interpret the results. ## Use the CLI and SDKs Use the [Straddle CLI](/developer-tools/cli/overview) to call the API from your terminal and return JSON for scripts and agents. [Choose an SDK](/developer-tools/sdks) to call the API from your application. # Build your first integration Source: https://docs.straddle.com/developer-tools/quickstart Use the Straddle Wizard to plan, build, and test Pay by Bank in your application. Add Straddle to your application with your coding agent. The Wizard guides the work from a plan you review to code changes and recorded sandbox test results. ## Before you begin Prepare the following: * An application repository and Node.js 22.18 or later. * Claude Code, Codex, or Cursor. For Auto mode, install and sign in to the client's command-line tool: `claude`, `codex`, or `cursor-agent`. * A sandbox API key from the [Straddle Dashboard](https://dashboard.straddle.com), available as `STRADDLE_API_KEY` in the environment that starts your agent. Use your secret manager or shell configuration to supply the API key. The [plugin installation guide](/developer-tools/agent-plugin/install) covers client setup and connection checks. ## Build and verify In a terminal at the repository root, select sandbox: ```bash theme={null} export STRADDLE_ENVIRONMENT=sandbox ``` If you set `STRADDLE_BASE_URL`, use `https://sandbox.straddle.com`. The Wizard reports conflicting environment settings before the request steps start. Launch the guided integration: ```bash theme={null} npx @straddlecom/wizard@latest ``` Confirm the detected language and framework. Choose charges, payouts, or both; your integration type; an SDK; and a notification path. Select **Not decided yet** for a choice you want to work through with the agent. Select your client and **Auto** to let the Wizard start it. In **Manual**, follow the displayed setup steps and paste the Wizard's generated message into your agent. Review and accept any plugin download or installation needed for the run. The agent checks the project and writes `straddle-integration-plan.md`. Give it the application context it asks for. For a charge integration, adapt this request in the agent session: Add Pay by Bank to this application's checkout. Follow the Straddle Wizard program for this repository. Identify how the app stores customers, collects payments, and receives payment updates. Ask me to resolve the integration type and bank connection method before writing the plan. Show the files you propose to change and the sandbox scenarios you will test. Read the plan's application changes, account rules, and test scenarios. Approve the plan when it matches the integration you want. If the repository already uses another payment provider, the Wizard also includes a migration step. The agent implements the approved plan, then runs its test workflow. Review each sandbox write preview, including the environment, acting account, operation, and payload, before approving it. Complete any application interaction the agent needs, such as connecting a bank through the Bridge widget. The agent records the checks it ran and any scenario that still needs attention in `straddle-test-evidence.md`. Inspect the saved run: ```bash theme={null} npx @straddlecom/wizard@latest status ``` Open `straddle-integration-report.md` for the code changes and `straddle-test-evidence.md` for the results. A finished Test step has `Status: complete` for the current approved plan. Review the latest run's scenario table and its `live-observed` evidence for sandbox behavior. Read `straddle-go-live-report.md` for the production readiness review and any remaining gaps. Review the changed files and the agent's **Verify before merging** checklist before merging your integration. ## Continue an unfinished run After resolving a missing setting, unanswered question, or failed check, continue from the same repository: ```bash theme={null} npx @straddlecom/wizard@latest resume ``` The Wizard reads the plan and reports to find the first unfinished step. See [Run and resume an integration](/developer-tools/wizard/integrate) for completion states, Manual mode, and finishing after sandbox testing. # Choose your tools Source: https://docs.straddle.com/developer-tools/routing Choose a guided integration, an agent skill, API tools, or a payment playbook. Start with the [Straddle Wizard](/developer-tools/quickstart) to build and test an integration with your coding agent. For a specific job, choose the tool that fits the result you need. ## Choose by task The following tools support integration work and payment operations. | You want to | Use | What you get | | - | - | - | | Build your first Straddle integration | [Wizard](/developer-tools/quickstart) | A guided plan, implementation, sandbox tests, and readiness review. | | Add Straddle skills to your coding agent | [Straddle plugin](/developer-tools/agent-plugin/install) | Integration instructions and connections to Docs MCP and API MCP. | | Plan, migrate, test, or review an integration | [Skills](/developer-tools/skills/catalog) | A focused workflow with a plan or report in your repository. | | Find a guide or API explanation from your agent | [Docs MCP](/developer-tools/mcp/docs-search) | Documentation search. | | Discover an API operation and send a request | [API MCP](/developer-tools/mcp/api-requests) | Operation details and requests authenticated with your API key. | | Call the API or automate terminal work | [Straddle CLI](/developer-tools/cli/overview) | Commands, JSON output, and local payment data. | | Call Straddle from application code | [SDKs](/developer-tools/sdks) | A client library for your application language. | | Investigate payments, returns, or funding | [Playbooks](/playbooks/overview) | A task walkthrough with commands and guidance for interpreting results. | API MCP supports requests allowed by your API key, including writes. Review the [authentication and permissions](/developer-tools/mcp/safety) before sending requests. ## Put the tools to work The Wizard coordinates the integration steps in your coding agent. The plugin supplies skills, and the skills use documentation, API tools, and your application code to carry out each step. Your application calls Straddle through an SDK or the HTTP API. Once payments are running, use the CLI and playbooks to investigate individual records or analyze synchronized data. Start in your application repository and review the resulting plan and test evidence. Choose a playbook by the question you need to answer. # Choose an SDK Source: https://docs.straddle.com/developer-tools/sdks Install a Straddle SDK and open the reference for your application language. Use a Straddle SDK to call the API from your application. Choose your language, install the package, and follow its client setup example. ## Install your SDK Each language reference covers request methods, response types, authentication, and error handling. Install the package for a TypeScript or JavaScript application: ```bash theme={null} npm install @straddlecom/straddle ``` Open the [TypeScript setup guide](https://github.com/straddle-build/straddle-typescript#usage) or [API reference](https://github.com/straddle-build/straddle-typescript/blob/main/api.md). Install the package in your Python environment: ```bash theme={null} pip install straddle ``` Open the [Python setup guide](https://github.com/straddle-build/straddle-python#usage) or [API reference](https://github.com/straddle-build/straddle-python/blob/main/api.md). Add the module to your Go project: ```bash theme={null} go get github.com/straddle-build/straddle-go ``` Open the [Go setup guide](https://github.com/straddle-build/straddle-go#usage) or [API reference](https://github.com/straddle-build/straddle-go/blob/main/api.md). Install the gem: ```bash theme={null} gem install straddle ``` Open the [Ruby setup guide](https://github.com/straddle-build/straddle-ruby#usage) or [API reference](https://github.com/straddle-build/straddle-ruby/blob/main/api.md). Add the package to your .NET project: ```bash theme={null} dotnet add package Straddle ``` Open the [.NET setup guide](https://github.com/straddle-build/straddle-dotnet#usage) or [API reference](https://github.com/straddle-build/straddle-dotnet/blob/main/api.md). ## Configure your application Load your sandbox API key in your backend process and pass it to the SDK client. Set the API base URL to `https://sandbox.straddle.com`. The setup guide for each language shows the client options and supported environment variables. For SaaS and marketplace integrations, include the account context required by each operation. See the [account-scope table](/developer-tools/mcp/account-scoping) for the `Straddle-Account-Id` rules. ## Build with your coding agent The [Straddle integration workflow](/developer-tools/quickstart) helps your coding agent choose an SDK, implement your payment flow, and test it in sandbox. For an existing integration, choose a task from the [skill catalog](/developer-tools/skills/catalog). # Choose a Straddle skill Source: https://docs.straddle.com/developer-tools/skills/catalog Find the skill and output for your integration task. Choose a skill by the result you need. The released Straddle plugin v0.1.2 includes eight task skills and one shared best-practices skill. ## Task skills Use the following names when asking your agent to run a skill: | Skill | Use it to | Result | | - | - | - | | `straddle-get-started` | Choose the product, integration model, SDK, and documentation for your repository. | Orientation and a recommended next skill. | | `straddle-setup` | Check your repository, CLI, SDK, environment, and MCP connections. | `straddle-setup.md` with readiness findings. | | `straddle-plan` | Define files, SDK methods, account rules, notifications, and tests before implementation. | `straddle-integration-plan.md` for your approval. | | `straddle-integrate` | Implement the approved plan and run approved sandbox setup. | Code changes and `straddle-integration-report.md`. | | `straddle-migrate` | Add Straddle code beside an existing provider integration. | `straddle-migration-plan.md`, approved code changes, and `straddle-migration-report.md`. | | `straddle-test` | Verify the finished integration against its approved integration or migration plan. | `straddle-test-evidence.md`. | | `straddle-go-live` | Review code, sandbox evidence, and operational setup for production readiness. | `straddle-go-live-report.md`. | | `straddle-audit` | Investigate an integration failure or review existing Straddle code. | `straddle-audit-report.md` with findings, evidence, and recovery steps. | Setup reports missing dependencies and configuration so you can resolve them. Integrate builds from an approved plan. Test records failures for follow-up through Integrate, and Audit changes code only after you approve a specific finding. ## Shared guidance `straddle-best-practices` supplies the product, account-scope, credential, SDK, and request rules used by the task skills. It also answers Straddle behavior questions. For a workflow that runs API operations, choose Integrate or Test. ## Add Straddle beside another provider Migrate includes guidance for Stripe, Plaid, Moov, Modern Treasury, Dwolla, Paya, Payliance, and other payment or bank-linking providers. It inspects the existing integration and asks which provider roles you want Straddle to handle. Review its migration plan before approving code changes. The existing provider path stays in place behind the switch you choose. Customer-data transfer and traffic cutover need their own plan. ## Run your chosen skill Follow [Use Straddle skills](/developer-tools/skills/use-kit) for client-specific invocation and the guided sequence. For payment investigations, use the separate [Playbooks catalog](/playbooks/overview). # Build with Straddle skills Source: https://docs.straddle.com/developer-tools/skills/overview Guide your coding agent through planning, implementation, testing, and review. Use Straddle skills to turn an integration task into a plan, code changes, and verification evidence. Each skill gives your coding agent a defined job and the Straddle references it needs to complete it. [Install the Straddle plugin](/developer-tools/agent-plugin/install) to add the skills and hosted MCP connections to your client. For a guided sequence, start the [Straddle Wizard](/developer-tools/wizard/overview) in your application directory. ## Choose your starting point Select the task that matches your project: Run Setup, approve a plan, and build and test your Straddle flow. Plan a change, add Straddle beside a provider, or audit existing code. Install the plugin in Claude Code, Codex, or Cursor. Check skill discovery, configuration, plans, and test results. ## Work from your application The skills inspect your repository and installed SDK to ground their suggestions in the code you use. They ask you to choose the integration model and notification path, then record those decisions in the plan. Application code uses the Straddle SDK. Docs MCP supplies documentation, API MCP discovers operations and performs permitted requests, and the CLI supplies diagnostics and sandbox helpers. [MCP permissions](/developer-tools/mcp/safety) explain how API access and skill instructions work together. ## Review the result Each stage produces something you can inspect: a setup report, an integration plan, a code diff, test evidence, or a readiness report. Review those artifacts before moving to the next stage. A passing test report describes the scenarios that ran; the report also records gaps that need follow-up. For questions about existing payments, choose a task from [Playbooks](/playbooks/overview). # Troubleshoot Straddle skills Source: https://docs.straddle.com/developer-tools/skills/troubleshooting Resolve missing skills, configuration gaps, blocked plans, and incomplete evidence. Use the skill's report and the Wizard's status to find the step that needs attention. ## Find a missing skill For a Wizard-managed installation, inspect the cached bundle and client installation: ```bash theme={null} npx @straddlecom/wizard@latest status --json npx @straddlecom/wizard@latest skill list ``` `skill list` lists the skills in the Wizard's bundle and may prompt to download a release. In `status`, check the selected client's `plugin.state` and `plugin.verified` fields. If the plugin is missing, follow [Install the Straddle plugin](/developer-tools/agent-plugin/install). For a mismatched Wizard-managed copy, update it and restart the client: ```bash theme={null} npx @straddlecom/wizard@latest update --client claude ``` Use `--client codex` for Codex. In Cursor, refresh the team marketplace and check the installed skill names in the IDE. The Wizard's status cannot verify Cursor team-marketplace installations. ## Resolve a marketplace conflict The Wizard stops if a marketplace named `straddle` points to a different directory from its verified plugin bundle. Choose whether to keep that installation or let the Wizard manage it. To switch to the Wizard, remove the existing Straddle plugin and marketplace through your client, then run the [installation steps](/developer-tools/agent-plugin/install). Keep your other marketplaces in place. ## Resolve a configuration finding Setup distinguishes missing configuration from checks that failed. Correct the named setting, then run Setup again: ```bash theme={null} npx @straddlecom/wizard@latest setup ``` For API MCP, supply `STRADDLE_API_KEY` to the coding client's process separately from the Straddle CLI's saved credentials. Check [MCP authentication](/developer-tools/mcp/safety) and select the sandbox environment explicitly. If discovery succeeds but an authenticated request fails, use [MCP troubleshooting](/developer-tools/mcp/troubleshooting). ## Unblock Integrate or Test Integrate needs an approved `straddle-integration-plan.md`. Test accepts an approved integration or migration plan and needs the corresponding code. Run Plan when the integration plan is missing. If the plan changed after approval, review the revised file and approve it again before continuing. Keep the approval attached to the current plan. ## Interpret incomplete test evidence Read the individual rows in `straddle-test-evidence.md`. A scenario can be blocked by missing configuration, waiting for approval, or require a person to complete a browser flow. The report names what ran and what still needs evidence. Correct the specific cause, then rerun Test. If a check found an implementation defect, return to Integrate before testing again. ## Audit an existing failure Ask your agent to investigate with Audit: Use the straddle-audit skill to investigate the Straddle failure in this repository. Ask me for the sanitized error and request ID if you need them. Write the findings and recovery steps to straddle-audit-report.md. Audit checks each finding against the installed SDK and API contract. Review its proposed fix before authorizing code changes. # Use Straddle skills Source: https://docs.straddle.com/developer-tools/skills/use-kit Run a guided integration or invoke a focused skill in your coding agent. Run the Straddle Wizard for a complete integration, or name a skill directly when you need one stage. ## Before you start [Install the Straddle plugin](/developer-tools/agent-plugin/install), open your application directory, and make your sandbox API key available to the coding client. Select the sandbox environment explicitly for integration work. The skills use your repository, installed SDK, and choices to define the integration. Have your integration model and, for a platform, the account you want to act for ready. ## Run a guided integration Start the Wizard from your application directory: ```bash theme={null} export STRADDLE_ENVIRONMENT=sandbox npx @straddlecom/wizard@latest ``` The Wizard runs Setup, Plan, Integrate, Test, and Go Live readiness. It adds Migrate after Plan when your application uses another payment provider. Select **Auto** to run the coding agent from your terminal, or **Manual** to receive a message for your own agent session. Follow [Build your first integration](/developer-tools/quickstart) for the plan review, sandbox approvals, and test evidence at each stage. To continue an interrupted program, run: ```bash theme={null} npx @straddlecom/wizard@latest resume ``` The Wizard resumes from the files the skills wrote. See [Run and resume an integration](/developer-tools/wizard/integrate) for the complete workflow. ## Invoke one skill Choose a name from the [skill catalog](/developer-tools/skills/catalog). For example, start a planning session: Enter the plugin's skill command in your project session: ```text theme={null} /straddle:straddle-plan ``` Ask Codex to use the installed skill: Use the straddle-plan skill to plan a Straddle integration in this repository. Ask Cursor to use the installed skill: Use the straddle-plan skill to plan a Straddle integration in this repository. Run the skill through the Wizard: ```bash theme={null} npx @straddlecom/wizard@latest skill run straddle-plan ``` ## Continue from the result Keep the plan and reports in the application repository. They carry decisions and evidence between stages. When Test reports a failure, ask Integrate to address it, then run Test again. When you need to diagnose code that already exists, run Audit and review its findings before approving fixes. # Wizard commands Source: https://docs.straddle.com/developer-tools/wizard/commands Run an integration, continue saved work, or select a focused Straddle skill. Run the Wizard from your application repository. Add a command after the package name to select a task: ```bash theme={null} npx @straddlecom/wizard@latest plan ``` ## Build and review The following commands run the complete program or one skill. | Command | Result | | - | - | | No command | Guided Setup, Plan, Integrate, Test, and Go Live readiness, with Migrate after Plan when another provider is detected. | | `setup` | Project and tool readiness report in `straddle-setup.md`. | | `get-started` | Guidance on the product, integration model, SDK, and documentation for your project. | | `plan` | Integration plan in `straddle-integration-plan.md`. | | `integrate` | Implementation of the approved plan and an integration report. | | `test` | Verification of the integration and `straddle-test-evidence.md`. | | `migrate` | A plan and implementation that add Straddle beside an existing payment provider. | | `go-live` | Production readiness review in `straddle-go-live-report.md`. | | `audit` | Review of an existing integration with findings in `straddle-audit-report.md`. | See the [skill catalog](/developer-tools/skills/catalog) for each workflow's prerequisites and outputs. Sandbox requests in Integrate and Test use the configured sandbox key and the skill's request previews and approvals. ## Continue and inspect Use the following commands for saved work. | Command | Result | | - | - | | `resume` | Continue at the first unfinished step from the plan and reports. | | `status` | Show the local bundle, client, plugin, MCP configuration, key presence, environment, and saved run. | | `status --json` | Return the status report as JSON, including `run` and `configurationErrors`. | | `log` | Write and open a local HTML view of recorded session events and available transcripts. | | `skill list` | List the selected bundle's skills and versions. It can prompt to download a plugin release. | | `skill run SKILL_NAME` | Run one named workflow skill. Use a name from `skill list`, such as `straddle-plan`. | `status` reads local state. Check the setup or test report's authenticated-read result when you need evidence that your API key works. ## Manage the plugin and MCP connections Select a client explicitly for configuration commands: ```bash theme={null} npx @straddlecom/wizard@latest install --client codex ``` The following commands show the proposed client configuration changes before running them. | Command | Result | | - | - | | `install` | Load the Straddle plugin through the client's installation path. | | `update` | Update the plugin to the release selected by the Wizard. | | `remove` | Remove the Straddle plugin and its marketplace entry. | | `mcp add` | Configure `straddle-api` and `straddle-docs` as needed for the client. | | `mcp remove` | Show or run the client's removal steps for the Straddle MCP connections. | Cursor configuration commands print steps to complete in the client. Follow [plugin installation](/developer-tools/agent-plugin/install) for client-specific details. ## Options Use the following options to select the project, client, or output. | Option | Use | | - | - | | `--dir PATH` | Work in the selected repository. Defaults to the current directory. | | `--client claude\|codex\|cursor` | Select the coding agent. | | `--mode auto\|manual` | Start the agent from the Wizard or receive a message to paste into your own session. Also changes the mode on `resume`. | | `--exclude GLOB` | Add a sensitive path to the Wizard's exclusions. Repeat for more paths. | | `--json` | Return JSON from `status` or `skill list`. | | `--yes` | Accept plugin downloads and installation, update, removal, or MCP configuration commands. Sandbox write approval remains part of the skill workflow. | | `--help` | Print command help. | | `--version` | Print the Wizard version. | Pass `--bundle PATH` to use a local Straddle skills directory. The Wizard labels it as a local bundle and checks that it has a compatible plugin structure. Use this option when testing changes to skills. # Run and resume an integration Source: https://docs.straddle.com/developer-tools/wizard/integrate Use Auto or Manual mode, review the results, and continue from the first unfinished step. Run the Wizard in your application repository to carry a Straddle integration through planning, implementation, sandbox testing, and production readiness review. Complete the [quickstart prerequisites](/developer-tools/quickstart#before-you-begin) first. ## Start the program Choose how the Wizard works with your coding agent. Start the guided run and select your installed, signed-in command-line client: ```bash theme={null} npx @straddlecom/wizard@latest --mode auto ``` The Wizard opens Claude Code, Codex, or `cursor-agent` in the terminal for the program. The agent continues through the listed steps and pauses when it needs your decision or approval. Prepare a message for the agent session you manage: ```bash theme={null} npx @straddlecom/wizard@latest --mode manual ``` Choose your client, follow the displayed setup steps, and paste the generated message into that agent. When the work stops, return to the Wizard and select **I'm back: read the files**, or run `resume` later. Confirm the project context and integration choices. The program runs Setup, Plan, Integrate, Test, and Go Live readiness. When the repository uses another payment provider, Migrate runs after Plan and writes its own plan and report. ## Review decisions as the agent works Read `straddle-integration-plan.md` before approving the proposed application changes and test scenarios. The agent records your approval against that version of the plan. An edit to the plan requires another review and approval. Review sandbox request previews separately from code changes. A preview identifies the environment, acting account, operation, and payload. The skill asks for approval before it sends the write. On a resumed run, it presents sandbox writes for approval again. Claude Code Auto runs show a checklist in the status line. Codex Auto runs show it on a local page whose address the Wizard prints. In Cursor and Manual runs, the Wizard reads the files after the session or when you return. ## Read the results The following files record the work at the repository root. | File | What to review | | - | - | | `straddle-setup.md` | Project readiness and unresolved configuration. | | `straddle-integration-plan.md` | Integration decisions, proposed changes, scenarios, and recorded approval. | | `straddle-migration-plan.md` and `straddle-migration-report.md` | The migration plan and implementation result, when Migrate runs. | | `straddle-integration-report.md` | Implementation results and remaining work. | | `straddle-test-evidence.md` | The latest test run, scenario results, authenticated reads, and observed sandbox resources. | | `straddle-go-live-report.md` | Production readiness and remaining gaps. | Reports after Plan identify the approved plan they used. The Wizard counts them as finished only when their completion status and plan hash match. Use the test evidence's `live-observed` rows to identify behavior verified against Straddle sandbox. Inspect progress or open the recorded session log: ```bash theme={null} npx @straddlecom/wizard@latest status npx @straddlecom/wizard@latest log ``` `status` shows the saved run and local configuration. `log` creates a local HTML page from recorded session events and available transcripts. Review the report and **Verify before merging** checklist with the code changes. ## Resume from the first unfinished step Continue from the same repository after resolving the finding or question that stopped the run: ```bash theme={null} npx @straddlecom/wizard@latest resume ``` The Wizard reads the plan and reports to choose the next step. In Auto, it reopens the agent session when a saved session ID is available, or starts a session at that step. In Manual, it prints the next message to paste. Change the mode with `resume --mode auto` or `resume --mode manual`. A partial or blocked report keeps its step unfinished. Changing an approved plan also makes reports for the earlier plan unfinished. Fix the reported issue and resume; the work already written stays in the repository. ## Finish after sandbox testing The Wizard offers **Finish here (skip Go Live)** when Test is complete and Go Live is the only remaining step, unless a Go Live report already exists for that plan. This records the skipped review in the run. When you're ready to assess production readiness, run: ```bash theme={null} npx @straddlecom/wizard@latest go-live ``` Read the readiness report and resolve its gaps before moving the integration to production. # Set up a project with the Wizard Source: https://docs.straddle.com/developer-tools/wizard/overview Check your repository, coding agent, and sandbox configuration before building an integration. Use the Straddle Wizard to prepare an application for integration work and run the Straddle skills in your coding agent. It detects project context, helps load the plugin, and records where the work stands. For the complete path from setup to sandbox results, follow [Build your first integration](/developer-tools/quickstart). ## Check project readiness Use Node.js 22.18 or later. Open the repository that will call Straddle, then start the focused setup workflow: ```bash theme={null} npx @straddlecom/wizard@latest setup ``` Check the detected language, framework, installed Straddle SDK, and existing payment provider. Correct the detected values when needed. Choose the payment operations, integration type, SDK, and notification path. Unresolved choices stay visible for the agent to discuss with you. Select Claude Code, Codex, or Cursor. In Auto mode, the Wizard starts the signed-in command-line client in your terminal. In Manual mode, it gives you the message and setup steps for your own agent session. The Wizard offers the plugin installation or update needed by the selected client. Cursor installation uses the steps shown in the client. See [Install the Straddle plugin](/developer-tools/agent-plugin/install) for each client's setup. The Setup skill writes `straddle-setup.md` at the repository root. Read its checks for the CLI, API key presence, environment, integration type, acting account, SDK, and MCP connections. Resolve any blocking finding, then run the setup command again to check the result. Setup records what is ready and what needs work in that report. ## Check configuration before requests Set `STRADDLE_API_KEY` in the environment that starts your agent and declare `STRADDLE_ENVIRONMENT=sandbox`. If you use `STRADDLE_BASE_URL`, set it to `https://sandbox.straddle.com`. The Wizard reads key presence and declared environment from these shell variables. A key saved only in the Straddle CLI's credential configuration needs to be supplied to the agent's environment as well. MCP discovery shows that your agent can find the server's tools. Use the setup report's authenticated-read result to check whether the key authorizes the requested API operation. These results appear separately in the report. ## Start the integration Once the project is ready, run the full program: ```bash theme={null} npx @straddlecom/wizard@latest ``` The program runs Setup, Plan, Integrate, Test, and Go Live readiness. It adds Migrate after Plan when it detects another payment provider. Follow the plan, approvals, and reports through an integration. Run planning, testing, migration, or review on its own. # Create paykeys from raw bank account details Source: https://docs.straddle.com/guides/bridge/bank-account Use the Straddle Bridge API to create paykeys directly from raw routing and account numbers without an open banking provider, with built-in verification. This guide provides a detailed walkthrough on using Straddle's Bridge API to create paykeys directly from bank account information. ## Implementation steps Ensure that bank account details such as the account number, routing number, and account holder's name are collected securely through your frontend. Use encryption or tokenization to protect sensitive data. Once the bank account details are collected, send the information to your backend server over a secure connection (e.g., HTTPS). Your server should handle the data safely and securely for further processing. On your backend, send a request to the Straddle Bridge API with the bank account details to create a paykey. Straddle returns a paykey that can be used for future transactions without needing to store sensitive bank information. Store the `paykey` securely in your system. You can use this `paykey` to create charges, initiate payments, or perform other transactions via Straddle's API in the future, without handling sensitive bank data again. ## Using Bridge with 'raw' bank account details To create a paykey using bank account details, make a POST request to the Straddle Bridge API. Here's the HTTP request details: ```bash Bridge a Bank Account theme={null} curl -X POST https://api.straddle.com/v1/bridge/bank_account \ -H "Authorization: Bearer YOUR_STRADDLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "routing_number": "011000138", "account_number": "123456789", "account_type": "checking", "metadata": { "user_reference": "user_12345" } } ``` Replace `YOUR_STRADDLE_API_KEY` with your actual Straddle API key, and fill in the appropriate values for `customer_id`, `routing_number`, `account_number`, and `account_type`. ## Handling the API response Upon successful creation of a paykey, the Straddle API responds with a JSON object. Here's an example of what you might receive: ```json theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******6789", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "BANK OF AMERICA, N.A. - *6789", "source": "bank_account", "institution_name": "BANK OF AMERICA, N.A.", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z" }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ``` # Create a paykey from a Mastercard token Source: https://docs.straddle.com/guides/bridge/mastercard-consent Use a Mastercard Open Finance connection for charges and payouts through Straddle. Use this guide after your customer connects a checking account through Mastercard Open Finance. Straddle uses that connection to retrieve account data, verify ownership, and return a [paykey](/guides/bridge/paykeys) for charges and payouts. Straddle calls the following values from one Mastercard consent receipt a *Mastercard token*: * Receipt ID. * Mastercard customer ID. * Mastercard account ID. Need a Mastercard token? See [Create a Mastercard token for Straddle](/integrations/open-banking/mastercard). ## Before you begin Complete the following: * [Create a customer in Straddle](/api-reference/customers/create). The customer cannot be `inactive` or `rejected`. * Use a Mastercard consent receipt that includes `moneyTransferDetails`, `accountOwner`, and `availableBalanceLive` for the same account. Mastercard does not include the account type in the consent receipt. Straddle records a paykey created from a Mastercard token as a `checking` account. ## Create the paykey Send the following IDs to `POST /v1/bridge/mastercard`. | Request field | What to send | | - | - | | `customer_id` | The Straddle customer ID. | | `mastercard.consent_receipt_id` | `data[].receipt.receiptId` from Mastercard. | | `mastercard.customer_id` | `data[].receipt.customerId` from Mastercard. | | `mastercard.account_id` | The `data[].receipt.products[].accountId` value for the selected account. | The Mastercard values must come from the same consent receipt. ```bash Create a paykey from a Mastercard token theme={null} curl --request POST https://sandbox.straddle.com/v1/bridge/mastercard \ --header "Authorization: Bearer YOUR_STRADDLE_API_KEY" \ --header "Content-Type: application/json" \ --header "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \ --data '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "mastercard": { "consent_receipt_id": "cr_4pfI2r1X8aOHrDDwrwC01NHTxOXlT1", "customer_id": "3465230025077724000", "account_id": "4633415743960374024" }, "external_id": "bank-connection-4412", "metadata": { "nickname": "Primary checking" } }' ``` For retry behavior, see [Idempotency keys for safe API retries](/api-reference/idempotency). `inline` processing is the default. If Straddle returns a `pending` paykey, processing continues asynchronously and Straddle sends status changes through [paykey webhook events](/webhooks/overview/events). ## Read the response An inline request that creates an `active` paykey returns `201 Created`. ```json theme={null} { "data": { "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "paykey": "2cd3e7b4.02.e271f11e0bd28fd609e5f7a426dabb2fc67646c7908ce8769c92c8c9448bce5e", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "external_id": "bank-connection-4412", "label": "FINBANK - *0725", "source": "mastercard", "institution_name": "FINBANK", "status": "active", "status_details": { "message": "Successfully matched account holder with customer.", "reason": "ok", "source": "system", "changed_at": "2026-09-01T18:35:12.4821903Z" }, "bank_data": { "routing_number": "011401850", "account_number": "**0725", "account_type": "checking" }, "balance": { "account_balance": 723419, "status": "completed", "updated_at": "2026-09-01T18:35:12.4821899Z" }, "config": { "processing_method": "inline", "sandbox_outcome": "standard" }, "metadata": { "nickname": "Primary checking" }, "created_at": "2026-09-01T18:35:12.4821897Z", "updated_at": "2026-09-01T18:35:12.4821903Z" }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f", "api_request_timestamp": "2026-09-01T18:35:12.4832104Z" }, "response_type": "object" } ``` Store `data.paykey` for charges and payouts. Straddle uses the available balance returned by Mastercard and falls back to the cleared balance when Mastercard does not return an available balance. Store the Mastercard token with the account connection. You'll need the consent receipt ID to revoke Mastercard access. ## Act on the paykey status Use `data.status` to decide the next action. | Status | Payment behavior | | - | - | | `active` | Create charges and payouts with the paykey. | | `review` | Create charges and payouts. Straddle holds the payments until review resolves. | | `pending` | Wait for asynchronous processing to finish before using the paykey. | | `rejected` | Do not use the paykey for charges or payouts. | For a `review` result, follow the [manual review process](/guides/bridge/paykeys#manual-review-process). See [Paykey status details](/guides/bridge/paykeys#paykey-status-details) for the full lifecycle. ## Recover from errors For an `inline` request, use the HTTP status code to decide how to handle the error. For asynchronous processing, use the paykey status from [paykey webhook events](/webhooks/overview/events). Treat `error.detail` and `status_details.message` as diagnostic text. Do not match their contents in code. Recognized Mastercard token failures return `422 Unprocessable Entity` during `inline` processing. Straddle maps them to these diagnostic messages: | Diagnostic message | Recovery | | - | - | | `The Mastercard consent is not valid for this account, or does not grant the access this request requires.` | Verify `mastercard.consent_receipt_id`, `mastercard.customer_id`, and `mastercard.account_id`. Confirm that the consent receipt includes all three required products for the account. | | `The Mastercard consent has been revoked.` | Create a new Mastercard token, then retry with a new idempotency key. | | `The Mastercard consent has expired.` | Create a new Mastercard token, then retry with a new idempotency key. | | `The Mastercard consent has reached its usage limit.` | Create a new Mastercard token, then retry with a new idempotency key. | | `Mastercard did not return ACH routing and account numbers.` | Use an account that returns the ACH details required to create a paykey. | | `Mastercard is not enabled.` | Ask your Straddle contact to enable Mastercard for the request environment. | | `Mastercard partner token is not available.` | Contact Straddle and include `meta.api_request_id`. | | `Customer not found.` | Verify the top-level `customer_id` and the account scope of your API key. | | `Cannot create paykey as customer is inactive.` or `Cannot create paykey as customer is rejected.` | Resolve the customer status or use an eligible customer. | | `Institution not found for routing number '...'.` | Contact Straddle and include `meta.api_request_id`. | During asynchronous processing, a failure listed in the table changes the paykey to `rejected` and sends a paykey webhook event. Other failures leave the paykey in `pending` while Straddle retries. During `inline` processing, a Mastercard failure that is not listed in the table returns `500 Internal Server Error`. Contact Straddle before retrying and include `meta.api_request_id`. ## Keep the Mastercard token available When you create the Mastercard token, set `maxCalls` and `accessPeriod` for each product. Mastercard's [Generate Third Party Access Key](https://developer.mastercard.com/open-finance-us/documentation/participant-model/partner-linked/client/client-steps/#operation/GenerateThirdPartyAccessKey) example uses `maxCalls: 200`. See [Set the token scope](/integrations/open-banking/mastercard#set-the-token-scope). Unless your use case has a set expiration date, set `accessPeriod.endTime` as far into the future as your Mastercard configuration allows. Contact Mastercard for more information about access periods and call limits. If the Mastercard token expires, is revoked, or reaches a call limit, Straddle cannot request a new balance. The paykey can remain `active` and keeps its last bank data and balance. If Straddle cannot refresh the balance for a charge, the outcome depends on the charge's `config.balance_check` value: * `disabled`: Straddle does not request a balance. * `enabled`: The charge can continue without a completed balance check. * `required`: The charge fails because Straddle cannot verify the balance. You cannot replace the Mastercard token on an existing paykey. If Mastercard returns a new consent receipt, create a new paykey and [cancel the old paykey](/api-reference/paykeys/cancel). ## Test in sandbox Create the Mastercard token in Mastercard's sandbox, then send the Bridge request to `https://sandbox.straddle.com`. Name matching runs when `config.sandbox_outcome` is `standard`. Set `config.sandbox_outcome` to `active`, `rejected`, or `review` to force that paykey status. Use expired, revoked, under-scoped, and exhausted Mastercard tokens to test the recovery paths. See [Sandbox testing for Pay by Bank](/guides/resources/sandbox-paybybank) for more scenarios. ## Disconnect the account Complete both actions when the customer disconnects the account: 1. Call Mastercard's [Revoke Third Party Access](https://developer.mastercard.com/open-finance-us/documentation/api-reference/#operation/RevokeThirdPartyAccessKey) operation with the consent receipt ID. 2. [Cancel the Straddle paykey](/api-reference/paykeys/cancel). Mastercard revocation stops future account data requests. Paykey cancellation stops future payment use through Straddle. Revoking the consent receipt alone does not cancel the paykey. # Bridge API overview Source: https://docs.straddle.com/guides/bridge/overview Use the Straddle Bridge open-banking platform to securely connect customer identities to bank accounts and generate paykeys for initiating ACH payments. Welcome to the comprehensive guide on **Bridge** and **Paykeys**, essential components of Straddle's **Pay by Bank** solution. This guide is designed to provide you with a deep understanding of how Bridge and Paykeys work together to facilitate secure, seamless account-to-account (A2A) payments. By integrating Bridge into your application, you can: * **Enable Open Banking Connections**: Allow customers to connect their bank accounts securely using Bridge. * **Identity-to-Account**: Generate Paykeys to match customer identities with bank account ownership details. * **Initiate Secure Payments**: Use Paykeys as secure tokens to initiate payments without exposing sensitive information. This narrative guide walks you through the concepts, processes, and best practices for integrating Bridge and Paykeys, ensuring a smooth and secure payment experience for your customers. ## What is Bridge? **Bridge** is Straddle's universal open banking solution that enables customers to connect their bank accounts seamlessly within your application. It serves as the gateway for establishing a secure link between the customer's verified identity and their bank account. Drop-in widget with connections to over 90% of U.S. banks via open banking, plus support for manual bank account entry Accept existing tokens from other open banking providers like Plaid, MX, and Finicity Create secure payment tokens linking verified identities to bank accounts Provide a seamless way for customers to connect their bank accounts Your application never touches sensitive account data, simplifying compliance with data protection regulations Dramatically reduce fraud risk by ensuring the person initiating a payment is the verified owner of the linked bank account Unlike other open-banking solutions, Bridge provides multiple ways to connect your application to bank accounts: An embeddable interface that allows customers to connect their bank accounts directly within your application. Use existing tokens from your existing open banking provider with support for "processor tokens" from Plaid, MX, and Finicity. Allow customers to manually enter their bank account details when open banking isn't an option. ## What are Paykeys? A **Paykey** is a new kind of payment token generated upon successful **Bridge** connection. It represents the verified linkage between the customer's identity and their bank account, enabling you to initiate payments securely without exposing sensitive financial information. The key innovation of Paykeys is that they cryptographically link a verified identity to confirmed bank account ownership. This linkage dramatically reduces fraud risk compared to traditional ACH payments. By ensuring the person initiating a payment is the owner of the bank account, Paykeys significantly reduce the risk of unauthorized transactions. Paykeys help meet KYC and AML requirements by tying verified identities to bank accounts, simplifying regulatory compliance. Sensitive bank details are never exposed, reducing the risk of data breaches and simplifying PCI DSS compliance. Once created, Paykeys can be reused for multiple transactions, streamlining the payment process for returning customers. Take a deep dive into the what and why of Paykeys [here](/guides/bridge/paykeys). ## How Bridge creates Paykeys From your perspective as a developer integrating with Straddle, the Paykey generation process via Bridge is streamlined and mostly handled internally by Straddle. Here's an overview of the steps involved: Create a customer using Straddle's Customers API. * You collect and submit basic customer information (name, email, phone, address) * Straddle performs robust identity verification and KYC/AML checks internally * You receive a `customer_id` for the verified customer Use Bridge to connect the customer's bank account. * Initiate the Bridge flow (widget, API, or manual entry) * Customer provides their bank account information through the chosen method * Bridge securely handles the bank account connection, extracting bank account numbers and ownership details Straddle performs crucial matching to link identity and account ownership. * Straddle compares the verified identity information with the bank account ownership details * The WALDO algorithm is used to check for name matches, address correlation, and other identifying factors * This step ensures that the person whose identity was verified is indeed the owner of the connected bank account Upon successful matching, Straddle generates the Paykey. * Straddle creates a secure, cryptographic token (the Paykey) that represents the verified identity-account linkage * The Paykey is returned to you via the Bridge API response Securely store and use the Paykey for payments. * Store the Paykey securely in your system * Use the Paykey to initiate payments via Straddle's Payments API Straddle handles the complex parts of this process internally, including robust identity verification, bank account validation, and the crucial identity-to-account ownership matching. This not only simplifies your integration but also provides a strong foundation for secure, low-fraud payments. ## Integrating Bridge into your application ### Step-by-step integration You must create a `customer` before you can connect with Bridge. View the [Customers API](/api-reference/customers/create) for more information. Decide how you want customers to connect their bank accounts: Use the embeddable widget for a seamless experience Use Bridge with tokens from providers like Plaid Allow manual input of bank details Follow the implementation guide for your chosen method: Add the following script tag to the `` of your HTML: ```html theme={null} ``` Make a POST request to generate a Bridge token: ```bash Request theme={null} curl -X POST https://api.straddle.com/v1/bridge/initialize \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{"customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705"}' ``` ```json Response theme={null} { "data": { "bridge_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.....1GKotLEn7JOEofzwd-559LpS3Mg-RlhqMerr1zA5HY0" }, "meta": { "api_request_id": "029758cc-d273-465c-aefe-2310407e153c" }, "response_type": "object" } ``` Add the following script to your page to initialize the Bridge widget: ```html theme={null}
```
In the `onSuccess` callback, you'll receive a paykey object. Here's an example of what it looks like: ```json theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******7890", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "BANK OF AMERICA, N.A. - *7890", "source": "straddle", "institution_name": "BANK OF AMERICA, N.A.", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z" }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ``` Send the entire callback payload to your backend and inspect `data.status` before beginning a downstream workflow. An `active` paykey is ready for payment origination; a paykey in `review` requires approval or rejection before you treat it as active. See [Handle the Widget Callback](/guides/bridge/widget#3-handle-the-widget-callback) for the complete integration guidance.
Use your existing integration with Plaid, MX, or Finicity to obtain a processor token for the customer's previously connected bank account. Make a server-side POST request to the Bridge API to create a Paykey using the third-party token: ```bash Create Paykey from Plaid Token theme={null} curl -X POST https://api.straddle.com/v1/bridge/plaid \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "plaid_token": "plaid_processor_token" }' ``` Use the Bridge API to create a Paykey from existing bank account details: ```bash Create Paykey from Bank Account theme={null} curl -X POST https://api.straddle.com/v1/bridge/bank_account \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cus_123456789", "account_holder": "John Doe", "routing_number": "110000000", "account_number": "000123456789", "account_type": "checking" }' ```
Store the Paykey securely and use it for future payment initiation. ```json Paykey Response Example theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******7890", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "BANK OF AMERICA, N.A. - *7890", "source": "straddle", "institution_name": "BANK OF AMERICA, N.A.", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z" }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ```
## Best practices * Always use HTTPS for all API calls and data transmissions. * Implement proper error handling to manage failed Paykey generations or bank connections. * Regularly rotate your API keys and use environment-specific keys (test/live). * Implement webhook handlers to receive real-time updates on Paykey and payment statuses. * Provide clear instructions and support for customers during the bank connection process. ## Frequently asked questions The Paykey generation process is highly secure, using BLAKE3 hashing, encryption, and strict access controls. Sensitive data is never exposed or stored in plain text. Yes, Paykeys are designed to be reusable for multiple payments, including one-time, recurring, and subscription payments. Ensure secure management and compliance with tokenization standards. Bridge accepts tokens from providers like Plaid, MX, and Finicity. By providing the token to Bridge, it can retrieve bank account details and generate a Paykey without requiring the customer to reconnect their bank account. If a mismatch is detected between the customer's verified identity and bank account ownership details, Paykey generation fails. Handle this gracefully by informing the customer and providing options to rectify the issue. ## Additional resources # Paykeys: secure tokens for bank payments Source: https://docs.straddle.com/guides/bridge/paykeys Paykeys are reusable tokens linking verified customer identities to bank accounts to enable secure ACH charges, payouts, and recurring bank payments. **Paykeys** are a cornerstone of Straddle's Pay by Bank stack. They are secure tokens that represent a customer's verified identity *and* their bank account. The creation of a Paykey involves advanced identity matching through Straddle's proprietary name matching algorithm (WALDO). This algorithm compares the customer's known identity (obtained via Straddle ID) with the account ownership details retrieved from the customer's financial institution through open banking. This ensures that the individual initiating the payment is the legitimate owner of the bank account, significantly reducing the risk of fraud. This guide explores how Paykeys work, the security measures in place, and how they integrate with other components of the Straddle ecosystem to facilitate secure payments. Verifies that the customer connecting the bank account is its legitimate owner Manages variations in PII, such as typos, nicknames, and cultural naming conventions Identifies and prevents potential fraudulent activities before they occur. Embeds regulatory compliance checks into the bank verification process ## How Bridge creates Paykeys Bridge is Straddle's connectivity platform that securely links customers' bank accounts to your application. When a customer connects their bank account through Bridge, a Paykey is generated to securely represent this connection. Here's how the process works: Before connecting a bank account, the customer is onboarded and their identity is verified using Straddle ID. This ensures compliance with KYC (Know Your Customer) and AML (Anti-Money Laundering) regulations. The customer connects their bank account using the Bridge Widget, an embeddable interface within your application. Alternatively, Bridge accepts existing tokens from providers like Plaid, MX, or Finicity, leveraging customers' pre-existing bank connections. Paykeys name matching is also possible with manual bank entry. WALDO is Bridge's proprietary algorithm for verifying bank account ownership. WALDO compares the customer's verified identity with the bank account ownership details The algorithm accounts for minor discrepancies, such as nicknames, middle names, typos, and cultural naming conventions. Prevent fraudulent activities and unauthorized access to bank accounts. The verification occurs instantly in the API response A Universally Unique Identifier (UUID) is generated to represent the link between the customer and their bank account. The UUID is hashed using a cryptographic hash function (BLAKE3) to ensure it cannot be reverse-engineered. The hashed value is encoded (e.g., Base64 or URL-safe encoding) to produce the Paykey. The result is a secure, unique token (the Paykey) that represents the customer-bank account linkage. Based on WALDO's verification results, the paykey is assigned an initial status: * active * rejected * review (requires manual review) The Paykey object is securely returned to your application. It includes the paykey, masked bank account details, the available balance, and the current verification status. Your application never has to transmit PII or bank account details to Straddle. The Paykey authorizes payments without exposing sensitive details. By integrating Bridge and utilizing the WALDO algorithm to create Paykeys, you provide a secure and efficient way to process payments, enhancing both security and user experience. ## Paykey object definition The **Paykey** object represents a secure, tokenized link between a customer and their bank account. It is used to authorize payments without exposing sensitive financial information. ## Paykey attributes | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for the paykey, generated by Straddle. | | `customer_id` | string | Unique identifier of the customer associated with this paykey. | | `label` | string | Human-readable label for the paykey, often including the bank name and masked account number. | | `source` | string | Method used to create the paykey (e.g., `bank_account`, `plaid`, `mx`, `straddle`). | | `institution_name` | string | Name of the financial institution associated with the paykey. | | `status` | string | Current status of the paykey (`pending`, `active`, `inactive`, `rejected`, `review`). | | `status_details` | object | Additional information about the paykey's status. | | ↳ `message` | string | A human-readable description of the current status. | | ↳ `reason` | string | A machine-readable identifier for the specific status. | | ↳ `source` | string | Identifies the origin of the status change (e.g., 'bank\_decline', 'system'). | | `paykey` | string | The tokenized paykey value used for transactions. | | `bank_data` | object | Masked bank account details associated with the paykey. | | ↳ `routing_number` | string | The bank's routing number. | | ↳ `account_number` | string | The masked bank account number (e.g., "\*\*\*\*\*\*1234"). | | ↳ `account_type` | string | The type of bank account (e.g., "checking" or "savings"). | | `balance` | integer | The available balance of the linked account in cents, if available. | | `metadata` | object | User-defined key-value pairs for storing additional information about the paykey. | | `expires_at` | datetime | Expiration date and time of the paykey, if applicable. | | `created_at` | datetime | Timestamp of when the paykey was created. | | `updated_at` | datetime | Timestamp of the most recent update to the paykey. | ## Verification results On paykey creation, Straddle performs name matching and determines whether the bank account is open and ready for transactions. The verification data Straddle uses to evaluate each paykey can be retrieved from the `/paykeys/{id}/review` endpoint. Use these insights to help you decide whether to `accept` or `reject` paykeys in `review` status, or to `cancel` `active` paykeys if needed. ## Review attributes | Field | Type | Description | | - | - | - | | `id` | string | Unique identifier for this verification record. | | `decision` | string | Overall verification decision (`accept`, `review`, or `reject`). | | `messages` | object | Key-value pairs of verification codes and their human-readable descriptions. | | `breakdown` | object | Detailed results for each verification check performed. | | ↳ `name_match` | object | Results from comparing the customer name to the matched name on the account. \*These fields will be null when an account is linked using account and routing number only. | | ↳ `names_on_account` | array | List of account holder names retrieved from the bank. | | ↳ `matched_name` | string | The name from the account that was compared to the customer name. | | ↳ `customer_name` | string | The customer's name. | | ↳ `correlation_score` | number | Numerical score representing name similarity (0-100). | | ↳ `decision` | string | Decision for this check (`accept`, `review`, or `reject`). | | ↳ `reason` | string | Human-readable explanation for the decision. | | ↳ `codes` | array | List of verification codes related to this check (e.g., `NM01`). | | ↳ `account_validation` | object | Results from account validation checks. \*These fields will be null when open banking tokens are used. | | ↳ `decision` | string | Decision for this check (`accept`, `review`, or `reject`). | | ↳ `reason` | string | Human-readable explanation for the decision (empty if accepted). | | ↳ `codes` | array | List of verification codes related to this check. | | ↳ `created_at` | datetime | Timestamp of when the verification was performed. | | ↳ `updated_at` | datetime | Timestamp of the most recent update to the verification record. | | `meta` | object | Request metadata. | | ↳ `api_request_id` | string | Unique identifier for this API request. | | ↳ `api_request_timestamp` | datetime | Timestamp of when the API request was processed. | | `response_type` | string | Type of response returned (typically `object`). | ## Paykey status details | Status | Description | | - | - | | `pending` | Initial status when the paykey is created and awaiting verification, or when reprocessing is triggered. | | `active` | Paykey has been verified and is ready for use in transactions. | | `review` | Paykey requires manual review due to verification issues (e.g., name variations). | | `inactive` | Paykey is no longer active and cannot be used for transactions. | | `rejected` | Paykey failed verification or was rejected by the financial institution. | * The `account_number` in the `bank_data` object is always masked for security reasons. Use the unmasked paykey data endpoint to access the full account number when necessary and authorized. * The `balance` field is only available for certain integration types and may not always be present. * The `source` field indicates the method used to create the paykey, which can affect the available features and verification process. * The `metadata` object can contain up to 20 key-value pairs, each with a maximum length of 40 characters for keys and 500 characters for values. * The `created_at` and `updated_at` fields are automatically managed by Straddle and cannot be modified directly. * The `expires_at` field is only applicable for certain types of paykeys and integration methods. * Paykeys in `review` status can be manually approved or rejected via PATCH `/paykeys/{id}/review`. * Use GET `/paykeys/{id}/review` (or confirm if different endpoint) to retrieve verification details. ### Example Paykey object ```json theme={null} { "id": "pk_1234567890abcdef", "customer_id": "cus_9876543210fedcba", "label": "Chase Checking (...1234)", "source": "bank_account", "institution_name": "Chase", "status": "active", "status_details": { "message": "Paykey is active and ready for use", "reason": "verified", "source": "system" }, "expires_at": "2024-12-31T23:59:59Z", "created_at": "2023-06-15T10:30:00Z", "updated_at": "2023-06-15T10:30:00Z", "paykey": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D", "bank_data": { "routing_number": "123456789", "account_number": "******1234", "account_type": "checking" }, "metadata": { "user_id": "user_5678", "account_nickname": "My Primary Checking" } } ``` ## Paykey verification and manual review When a paykey is created, it goes through an automated verification process that can result in one of three decisions: Immediate Approval The paykey passes all verification checks and is ready for use in payments immediately. Manual Review Required The paykey has verification issues (e.g., name variations) that require human review before approval. Verification Failed The paykey fails verification due to significant issues and cannot be used for payments. ### Verification codes and their meaning A paykey's verification decision and status are determined by the codes it receives during processing. If any rejection code is present, the paykey is `rejected` regardless of other successful verification results. Other codes result in the paykey status being transitioned to `review`. Paykeys that pass verification become `active`. Paykeys must be in `review` status to have their verification outcome modified. | Straddle Code | Meaning | | :- | :- | | **NM01** | Account Holder is not a match for Customer. | | **BR104** | The bank account owner's information does not match with the information provided. | | Straddle Code | Meaning | | :- | :- | | **BR101** | The bank account is either closed, invalid, or in a negative status | | **BR102** | The bank account is either ineligible for debit activity or deemed to have a high probability of return | | **BR105** | The bank account requested for verification has not been contributed by the participant bank | | **BR106** | The bank account has been closed as a result of unacceptable use by the customer | | **BR107** | The bank account has been removed from the Contributor's source | | **BR108** | The bank account will not accept any debit activity | | **BR109** | The bank account has been closed and removed from the Contributor's source | | **BR110** | The bank account is closed in the last processing cycle | | **BR111** | The bank account has a history of available balance being less than zero | | **BR112** | The bank account provided is not a demand deposit account (non-DDA account) | | **BR113** | The bank account has a high probability of return | | **BR114** | Likely an invalid account number/routing number | | **BR115** | Bank account owner information does not match with the information provided (open banking) | | **BR116** | Bank Data Provider returned invalid owner information error | | **BR117** | Bank Data Provider returned invalid length for account number and routing number error | | **BR119** | The bank account owner's DOB doesn't match with the bank data provider | | **BR120** | The bank account owner's SSN or tax ID doesn't match with the bank data provider | ### Manual review process Manual paykey review gives you control over verification decisions. When a paykey has a `review` status, you can evaluate verification details and make informed decisions about whether to approve or reject the paykey, either through the dashboard or programmatically. This helps you prevent fraudulent accounts, manage risk, and ensure only legitimate payment methods are activated on your platform. Name information is only available for paykeys linked through Open Banking. Paykeys connected using account and routing number don't include account holder name data, so `name_match` fields in the review response are `null`. Use Open Banking connections where possible to enable full name verification at review time. You can view all paykeys requiring review at the bottom of the [Overview](https://dashboard.straddle.com) page, or update their status programmatically using the review endpoint: 1. **Review Details**: Access detailed verification information that may include names on the bank account and matched name in the dashboard or retrieve it from the `review` endpoint. 2. **Manual Decision**: Resolve the paykey status by setting it to `active` or `rejected`. 3. **Retry Verification**: Optionally refresh the verification process to re-evaluate the paykey. The review process ensures that edge cases and minor discrepancies don't automatically reject legitimate paykeys, while maintaining security standards. **Payment Processing During Paykey Review** Payments are held while paykeys are under review. All transactions associated with a paykey in review status are held until the paykey is either approved or rejected. Review paykeys promptly to avoid payment backlogs. Delayed reviews can cause multiple payments to queue up and process simultaneously once the paykey is approved. This can result in unexpected batch processing of charges or payouts for a single account. **Paykey Review Response** Sample responses from the `/paykeys/{id}/review` endpoint. Accounts linked via open banking show `null` for account validation details because validation is performed by the open banking provider. However, the same validation checks are still conducted. They're just handled upstream by the provider rather than Straddle. ```json theme={null} { "data": { "paykey_details": {...}, "verification_details": { "id": "019a1743-d6db-7771-8f7f-09e43a08d1c8", "decision": "accept", "messages": {}, "breakdown": { "name_match": { "decision": "accept", "reason": "Successfully matched account holder with customer.", "codes": [], "matched_name": "John Michael Doe", "customer_name": "John Doe", "correlation_score": 0.95, "names_on_account": [ "John Michael Doe", "Jane Doe" ] }, "account_validation": { ... } }, ... } } } ``` ```json theme={null} { "data": { "paykey_details": {...}, "verification_details": { "id": "01995295-954b-73cd-bd55-74dfff6ef4c6", "decision": "reject", "codes": ["BR101"], "messages": { "BR101": "The bank account is either closed, invalid, or in a negative status." }, "breakdown": { "name_match": {...}, "account_validation": { "decision": "reject", "reason": "The bank account is either closed, invalid, or in a negative status. Derived using the routing number and account number.", "codes": ["BR101"] } }, ... } } } ``` An account that is linked using account and routing number has a null name match object since this data is not returned by the provider. Straddle recommends using an open banking login where possible. ```json theme={null} { "data": { "paykey_details": {...}, "verification_details": { "id": "456e7890-e89b-12d3-a456-426614174001", "decision": "review", "messages": { "NM01": "Account Holder is not a match for Customer." }, "breakdown": { "name_match": { "decision": "review", "reason": "Account Holder is not a match for Customer.", "matched_name": "John Smith", "correlation_score": 0.10, "names_on_account": ["John Smith", "Jane Smith"] }, "account_validation": {...} }, ... } } } ``` ## Account balance updates For accounts linked using an open banking token or Bridge, you can receive balance updates when the following events occur: * When a new Paykey is created * When the new [refresh](https://straddle.dev/api-reference#tag/paykeys/PATCH/v1/paykeys/\{id}/refresh_balance) endpoint is explicitly called, at most once per hour * When a charge or payout is created You receive the balance update within a [Paykey webhook event](https://straddle.dev/api-reference#webhook/post/paykeyeventv1). **Manually trigger balance updates:** You can also trigger a balance refresh by calling our new `/paykeys/{id}/refresh_balance` endpoint. ## Using Paykeys Paykeys are used in place of customer and bank account details when creating charges or payouts. Here's an example of creating a charge using a paykey: ```shellscript theme={null} curl -X POST https://sandbox.straddle.com/v1/charges \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paykey": "a1b2c3***.02.******x9y8z7", "amount": 1000, "currency": "usd", "description": "Monthly subscription fee", "payment_date": "2023-06-01", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "charge_123", "config": { "balance_check": "enabled" } }' ``` ## Ongoing management & unblocking When a Paykey is blocked (e.g., R29), your customer can't pay or get paid until it's fixed. Unblock in the Dashboard once they've updated their bank settings, with no support wait, so they can use the Paykey again quickly. View blocked Paykeys in the [Overview](https://dashboard.straddle.com/) tab or manage them directly from the specific Customer page. Paykey Unblocking Use the new `PATCH /v1/paykeys/{id}/unblock` endpoint to programmatically reactivate eligible Paykeys. ### Handling R29 returns Corporate "positive pay" blocks often cause R29 returns; you can now confirm the customer has added your ACH identifier to their approved list and select "Unblock Paykey" in the Dashboard. ## Benefits of Paykeys ### For businesses Prevent unauthorized account use and save on potential fraud-related losses. Simplify adherence to KYC and AML regulations. Automate identity matching, reducing the need for manual reviews while providing human oversight for edge cases. Enhance reputation by ensuring secure transactions. ### For customers Protect customers from unauthorized use of their bank accounts. Eliminate the need for additional verification steps in most cases. Ensure personal data is handled securely and used appropriately. Build trust in the platform's ability to protect financial information. ## Further reading * [Paykeys API Reference](/api-reference/paykeys) # Create paykeys from Plaid processor tokens Source: https://docs.straddle.com/guides/bridge/plaid-token Exchange Plaid processor tokens for Straddle paykeys to enable verified ACH charges and payouts for customers connected through Plaid Link. This guide provides a detailed walkthrough on integrating Plaid with Straddle to create paykeys for account-to-account payments. By leveraging Plaid's bank connections and Straddle's payment infrastructure, you can offer a seamless and secure payment experience to your users. ## Prerequisites Before you begin, ensure you have: * A Straddle account with API access * A Plaid account with API access ## Implementation steps Integrate Plaid Link into your frontend to allow users to securely connect their bank account. Plaid Link is the front-end module that facilitates the connection between the user's bank account and your application. Once the user connects their bank account using Plaid Link, Plaid returns a public token. Exchange this public token for an access token via Plaid’s API, which allows you to access the user's account information. With the access token obtained from Plaid, request a Straddle processor token from Plaid. This token allows you to link the user's bank account to Straddle's payment processing system. Pass the Straddle processor token to Straddle's Bridge API. Straddle returns a `paykey` which is linked to the user's bank account, allowing future transactions to be processed. Store the `paykey` securely in your system. Use this `paykey` to create charges, initiate payments, or perform other transactions via Straddle's API in the future. ## Setting up Plaid ### Create a `link_token` In order to integrate with Plaid Link, you first need to create a `link_token`. A `link_token` is a short-lived, one-time use token that is used to authenticate your app with Link. To create one, make a [`/link/token/create`](https://plaid.com/docs/api/link/#linktokencreate) request with your `client_id`, `secret`, and a few other required parameters from your app server. View the [`/link/token/create`](https://plaid.com/docs/api/link/#linktokencreate) documentation for a full list of `link_token` configurations. To see your `client_id` and `secret`, visit the [Plaid Dashboard](https://dashboard.plaid.com/developers/keys). ```curl theme={null} curl -X POST https://sandbox.plaid.com/link/token/create \ -H 'Content-Type: application/json' \ -d '{ "client_id": "${PLAID_CLIENT_ID}", "secret": "${PLAID_SECRET}", "client_name": "Plaid Test App", "user": { "client_user_id": "${UNIQUE_USER_ID}" }, "products": ["auth"], "country_codes": ["US"], "language": "en", "webhook": "https://webhook.example.com", "redirect_uri": "https://domainname.com/oauth-page.html" }' ``` **Integrate with Plaid Link** Once you have a `link_token`, all it takes is a few lines of client-side JavaScript to launch Link. Then, in the `onSuccess` callback, you can call a simple server-side handler to exchange the Link `public_token` for a Plaid `access_token` and a Straddle `processor_token`. ```javascript theme={null} ``` ## Obtaining a Straddle processor token from Plaid Once you have the access token, you can use it to obtain a Straddle processor token. This token is specific to Straddle and allows secure communication between Plaid and Straddle. ```javascript theme={null} # Exchange the public token from Plaid Link for an access token. curl \ -H 'Content-Type: application/json' \ -d '{ "client_id": "${PLAID_CLIENT_ID}", "secret": "${PLAID_SECRET}", "public_token": "${PUBLIC_TOKEN}" }' \ -X POST \ https://sandbox.plaid.com/item/public_token/exchange # Create a processor token for a specific account id. curl \ -H 'Content-Type: application/json' \ -d '{ "client_id": "${PLAID_CLIENT_ID}", "secret": "${PLAID_SECRET}", "access_token": "${ACCESS_TOKEN}", "account_id": "${ACCOUNT_ID}", "processor": "straddle" }' \ -X POST \ https://sandbox.plaid.com/processor/token/create ``` Note that `'straddle'` is the specific processor you're requesting the token for. This tells Plaid to generate a token compatible with Straddle's systems. ## Using the Straddle Bridge API with Plaid token Once you have obtained the Straddle processor token from Plaid, you can use it to create a paykey via Straddle's Bridge API. Here's the correct HTTP request format: ```bash Bridge a Plaid Token theme={null} curl -X POST https://api.straddle.com/v1/bridge/plaid \ -H "Authorization: Bearer YOUR_STRADDLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "plaid_token": "processor-sandbox-123abc...", "metadata": { "nickname": "My Bank Account" } }' ``` Replace `YOUR_STRADDLE_API_KEY` with your actual Straddle API key, and fill in the appropriate values for `customer_id` and `plaid_token`. The `metadata` field is optional but can be useful for storing additional information related to the Plaid account. When creating a paykey, the account holder's name is matched against the customer's name. Therefore, when using a Plaid token, to get an active paykey, the customer's name must match the Plaid token's account holder's name. In sandbox, the Plaid account holder's name is usually defaulted to **Alberta Bobbeth Charleson**. This can be changed in the Plaid system. In sandbox, this behavior can be overridden by specifying a [sandbox outcome](/guides/resources/sandbox-paybybank) in the request. ## Handling the Straddle API response The Straddle API responds with a paykey object. Here's an example of what you might receive: ```json theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******7890", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "CHASE BANK - *7890", "source": "plaid", "institution_name": "CHASE BANK", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z", "metadata": { "plaid_account_id": "5f7a8b9c0d1e2f3g4h5i6j7k" } }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ``` Note that the `source` field is set to "plaid" in this case, indicating that the paykey was created using a Plaid token. You should store this paykey securely for future use in transactions. ## Best practices and security considerations 1. **Token Security**: Never expose Plaid access tokens or Straddle processor tokens to the frontend. Always handle these server-side. 2. **Error Handling**: Implement robust error handling for both Plaid and Straddle API calls. 3. **Metadata Usage**: Use the metadata field to store relevant information, such as the Plaid account ID, for future reference. 4. **Token Refreshing**: Be aware of token expiration policies for both Plaid and Straddle. Implement token refresh mechanisms as needed. 5. **Compliance**: Ensure you're complying with both Plaid and Straddle's terms of service and data handling requirements. 6. **Logging**: Implement comprehensive logging for debugging and audit purposes, but be careful not to log sensitive information. ## Troubleshooting common issues 1. **Invalid Processor Token**: Ensure you're using 'straddle' as the processor when requesting the token from Plaid. 2. **Authentication Errors**: Double-check your API keys for both Plaid and Straddle. 3. **Expired Tokens**: If you're getting authentication errors, your tokens might have expired. Implement a token refresh mechanism. 4. **Account Not Supported**: Some bank accounts may not be supported for ACH transactions. Handle these cases gracefully in your UI. 5. **Rate Limiting**: Be aware of rate limits on both Plaid and Straddle APIs. Implement appropriate backoff strategies if you hit these limits. By following this guide, you should be able to successfully integrate Plaid with Straddle, leveraging the strengths of both platforms to provide a robust, secure payment solution for your users. # Create paykeys from Quiltt tokens Source: https://docs.straddle.com/guides/bridge/quiltt-token Exchange Quiltt processor tokens for Straddle paykeys to enable verified ACH charges and payouts for customers connected through the Quiltt platform. ## Prerequisites Before you begin, ensure you have: * A Straddle account with API access * A Quiltt account with processor token capabilities * Quiltt Connector configured with `ACCOUNT_NUMBERS` and `ACCOUNT_BALANCE_REFRESHES` features For a complete integration guide including Quiltt Connector setup, see our [detailed Quiltt integration guide](/integrations/open-banking/quiltt). ## Quick start Follow these steps to create a paykey from a Quiltt processor token. ### Step 1: Obtain a Quiltt processor token After your user connects their bank account through Quiltt Connector, create a processor token: ```bash theme={null} curl https://api.quiltt.io/v1/accounts/{accountId}/processor_tokens \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {QUILTT_API_KEY}' \ --data '{ "processor": "STRADDLE", "issuer": "QUILTT" }' ``` ### Step 2: Create a Paykey via Bridge API Use the processor token to create a paykey: ```bash theme={null} curl -X POST https://api.straddle.com/v1/bridge/quiltt \ -H "Authorization: Bearer YOUR_STRADDLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "quiltt_token": "processor-sandbox-123abc...", "metadata": { "nickname": "My Bank Account" } }' ``` ### Step 3: Handle the response A successful response returns the paykey and associated bank data: ```json theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******7890", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "CHASE BANK - *7890", "source": "quiltt", "institution_name": "CHASE BANK", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z", "metadata": { "quiltt_connection_id": "conn_5f7a8b9c0d1e2f3g4h5i6j7k", "quiltt_account_id": "acc_1a2b3c4d5e6f7g8h9i0j" } }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ``` Store the `paykey` securely for future transactions. Use it to [create charges](/api-reference/charges/create) and Straddle verifies the account balance before processing. ## Implementation flow User connects their bank account via Quiltt Connector Fetch account details using Quiltt's GraphQL API Create processor token for selected account Bridge processor token to create Straddle paykey Store paykey for payment processing ## Troubleshooting Common issues and their solutions: | Issue | Solution | | - | - | | Invalid processor token | Ensure `processor: "STRADDLE"` and `issuer: "QUILTT"` | | Authentication errors | Verify your Quiltt API key and Straddle API key | | Missing features | Enable `ACCOUNT_NUMBERS` in Quiltt Connector | | Connection not active | Wait for connection status to be `active` | # Bridge widget for connecting bank accounts Source: https://docs.straddle.com/guides/bridge/widget Embed the Straddle Bridge widget in your app for a drop-in UI that securely connects customer bank accounts and returns paykeys for ACH payments. The Bridge widget allows users to securely connect their bank accounts to your application. Unlike other open banking providers, Straddle handles data exchanges, retrieves bank details and owner information, and generates a secure payment token, all without exposing sensitive information to your frontend. Bridge Connection Before interacting with the Bridge widget, ensure you have created a customer in Straddle. For details on customer creation, see the [Customers Guide](/guides/identity/customers). ## Overview Users click a button or link to initiate the process. Return the session's `bridge_token` to your client application. Pass the `bridge_token` to your implementation of Bridge. Process the response and save the generated [paykey](/guides/bridge/paykeys) after successful account linking. ``` ## URL parameters Your unique Straddle platform identifier. This is used to associate the embedded form with your specific account or configuration. A string value representing the Straddle environment in which form submissions are created (e.g., `production`, `sandbox`). A unique identifier provided by the integrating application. Useful for cross-referencing the submission between Straddle and an external system. Aligns the content of the iframe to the left when set to `1`. Hides the default title of the embedded form when set to `1`. Makes the form background transparent when set to `1`. Enables automatic height adjustment based on content when set to `1`. ### How it works The standard implementation automatically handles the loading and initialization of the embed form: The script checks if the Straddle embed library is already loaded Once loaded, it initializes any uninitialized embeds on the page Built-in error handling ensures graceful fallback if issues occur ## Load on user interaction The example above uses an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE). That function doesn't have to be invoked right away, you can choose to name it and call it on user action. ```javascript theme={null} function initStraddleEmbed() { 'use strict'; // ... initStraddleEmbed(); } } document.getElementById('myButton').addEventListener('click', initStraddleEmbed); ``` ## Customization options ### Iframe attributes Controls iframe loading behavior. Set to `"lazy"` to defer loading until the iframe is near the viewport, improving performance. Sets the iframe width. Default is `"100%"` for responsive layouts. Can be set to specific pixel values (e.g., `"800px"`). Sets the initial iframe height. Default is `"500"`. When using `dynamicHeight=1`, this serves as the minimum height. Set to `"0"` to remove the default iframe border. Accessibility title for the iframe. Choose a descriptive title that explains the form's purpose. ### Script configuration When set to `true`, enables console logging for debugging purposes. Should be set to `false` in production. URL of the Straddle embed script. Should not be changed unless instructed by Straddle support. Set `isDebugMode = true` in the initialization script to enable detailed console logging. This helps diagnose initialization issues and verify proper embed loading. Remember to disable debug mode before deploying to production. ## Troubleshooting If you encounter issues: 1. Verify your platform ID is correctly set 2. Enable debug mode to get detailed logging 3. Check browser console for error messages 4. Verify the initialization script executes at the appropriate time 5. Test in multiple browsers to ensure compatibility # Manage linked bank accounts for users Source: https://docs.straddle.com/guides/embed/linked-bank-accounts Connect, verify, and manage external bank accounts for your platform users to enable settlements, payouts, and funding deposits through Straddle. Managing Linked Bank Accounts is crucial for your users' payment operations. These accounts serve as the source and destination for funding activities, playing a vital role in the financial ecosystem of your platform. Linked Bank Accounts connect your users' Straddle accounts and their external bank accounts. They serve several critical purposes: Linked accounts act as the destination for charges, where Straddle deposits settlements. They provide a source for payouts, enabling users to transfer funds from their external bank accounts to customers. Linking a bank account helps verify the identity and legitimacy of your users, adding an extra layer of security to your platform. Multiple linked accounts allow users to separate funds for different purposes (e.g., operating expenses vs. payroll). An account can have up to 3 `active` linked bank accounts. One for charge deposits, one for payout withdrawals, and one for Straddle billing. ## Create a linked bank account To allow your users to link a bank account, you'll need to implement a flow that collects the necessary information and sends it to Straddle via the API. Here's how you might implement bank account linking in your platform: Create a secure form in your UI to collect bank account information. Use the Create Linked Bank Account endpoint to send the collected information to Straddle. Process the API response, storing the linked\_bank\_account\_id for future reference. Update your UI to show the newly linked bank account and its status. ### Required information | Field | Description | | - | - | | account\_id | The Straddle account ID of your user | | account\_holder | Name on the bank account | | routing\_number | Bank routing number | | account\_number | Bank account number | ### Example request ```javascript Create a Linked Bank Account theme={null} async function linkBankAccount(userId, bankDetails) { try { const res = await fetch('https://api.straddle.com/v1/linked_bank_accounts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_STRADDLE_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ account_id: userId, // Your user's Straddle account ID bank_account: { account_holder: bankDetails.accountHolder, routing_number: bankDetails.routingNumber, account_number: bankDetails.accountNumber } }) }) return await res.json() // Contains the linked_bank_account_id and status } catch (error) { console.error('Error linking bank account:', error); throw error; } } ``` ## Managing linked bank account statuses As a platform, you need to handle various statuses of linked bank accounts and guide your users accordingly. ### Status workflow Initial state after the linked bank account is created in the system. Verification process is in progress. The account is being checked and validated. The linked bank account has been successfully verified and is ready for use in transactions. The linked bank account has failed the verification process. It cannot be used for transactions. A previously active linked bank account that has been deactivated. It can no longer be used for transactions. The status of a linked bank account determines its usability for transactions. Only accounts in the 'Active' state can be used for financial operations. ### Handling different statuses * Display a "Verification in Progress" message in your UI * Provide information about the verification process and estimated time * Disable any funding operations using this account until verification is complete * Update UI to show the bank account is ready for use * Enable features that require a verified bank account (e.g., charges, payouts) * Allow users to set this as their default funding source or payout destination * Notify the user about the failed verification * Provide options to re-enter bank details or try a different account * Explain the impact on their ability to perform funding operations * Inform the user that the bank account has been deactivated * Offer options to link a new bank account * If this was a default funding source, prompt user to choose a new one Always make it clear to users that they should only link bank accounts they own and have the authority to use for business purposes. This is crucial for maintaining the integrity of funding operations and complying with financial regulations. ## Troubleshooting common issues As a platform, you may encounter these common issues when users are linking bank accounts or performing funding operations: 1. **Invalid Routing Numbers**: Implement client-side validation for routing number format. 2. **Account Already Linked**: Check if an account is already linked before attempting to link it again. 3. **Verification Timeouts**: Handle cases where verification takes longer than expected, providing status updates to users. 4. **Insufficient Funds**: Clearly communicate when an ACH debit fails due to insufficient funds and provide guidance on next steps. 5. **Daily Limits**: Inform users about daily limits on ACH debits or payouts and track these limits in your platform. Remember, as a platform integrating with Straddle Embed, you're responsible for creating a user-friendly experience for bank account linking and funding operations while adhering to Straddle's security and compliance requirements. Always refer to the latest Straddle API documentation for the most up-to-date integration details. # Onboard merchants with Straddle Embed Source: https://docs.straddle.com/guides/embed/onboarding Build a custom merchant onboarding flow with Straddle Embed APIs, including KYB verification, representative collection, and bank account linking. ## Introduction This guide provides a detailed overview of the Straddle Embed onboarding process, focusing on the data model, object relationships, and implementation options. It is designed to help developers understand and implement the onboarding flow effectively. ## Onboarding options Straddle offers two approaches for merchant onboarding: For sophisticated platforms requiring full control and customization. For platforms seeking rapid market entry with pre-built components. ## API flow The API flow is designed for platforms with specific requirements and the technical resources to implement a fully customized onboarding experience. The API flow should only be used by sophisticated platforms with the necessary development resources and compliance expertise. ### Data model overview The onboarding process involves several interconnected objects: Top-level entities that can contain multiple accounts. Organizations allow for centralized management and grouping of related accounts. Represent individual merchants or businesses using Straddle services. Each account belongs to an organization and can have multiple representatives and linked bank accounts. Individuals associated with an account, typically with legal authority or significant responsibility within the business. Each account must have at least one representative. External bank accounts connected to a Straddle account for payment operations. These are essential for facilitating transactions and fund transfers. Manage Straddle features and payment settings for an account. These objects form a hierarchical structure, with Organizations at the top level. ### Object relationships Contains one or more Accounts Belongs to an Organization Belongs to an Account Belongs to an Account ### Detailed object descriptions #### Organizations Organizations serve as the top-level container for Accounts. They allow for centralized management of multiple Accounts. Key properties: * `id`: Unique identifier * `name`: Organization name * `external_id`: Your system's identifier (optional) #### Accounts Accounts represent individual merchants or businesses using Straddle services. Key properties: * `id`: Unique identifier * `organization_id`: Associated Organization * `type`: Account type (e.g., 'business') * `status`: Current account status * `business_profile`: Business details * `capabilities`: Enabled features #### Representatives Representatives are individuals associated with an Account, typically with legal authority or significant responsibility. Key properties: * `id`: Unique identifier * `account_id`: Associated Account * `first_name`: First name * `last_name`: Last name * `email`: Email address * `phone`: Phone number * `relationship`: Role within the organization #### Linked bank accounts Linked Bank Accounts connect external bank accounts to a Straddle Account for payment operations. Key properties: * `id`: Unique identifier * `account_id`: Associated Account * `status`: Current status * `bank_account`: Bank account details #### Capabilities Capabilities allow you to define the types of payments (and their associated limits), customers, and consent mechanisms that can be used by an Account for payment operations. Key properties: * `id`: Unique identifier * `account_id`: Associated Account * `status`: Current status * `settings` ```json theme={null} "charges": { "enable": true, "max_amount": 1, "daily_amount": 1, "monthly_count": 1, "monthly_amount": 1 }, "payouts": { "enable": true, "max_amount": 1, "daily_amount": 1, "monthly_count": 1, "monthly_amount": 1 }, "internet": { "enable": true }, "individuals": { "enable": true }, "businesses": { "enable": true }, "signed_agreement": { "enable": true } } ``` ### API onboarding flow Use the `POST /v1/organizations` endpoint Use the `POST /v1/accounts` endpoint, referencing the Organization Use the `POST /v1/representatives` endpoint, referencing the Account Use the `POST /v1/linked_bank_accounts` endpoint, referencing the Account Use the `POST /v1/capability_requests` endpoint, referencing the Account Use the `POST /v1/accounts/{account_id}/onboard` endpoint ### API considerations * Use the `Straddle-Account-Id` header for multi-tenant operations * Implement proper error handling for each API call * Utilize webhooks for asynchronous updates on onboarding status changes Refer to the [API Reference](/api-reference) for detailed endpoint specifications and request/response formats. ## Hosted flow For platforms looking to go to market quickly, Straddle offers a hosted flow with pre-built form components. This solution provides: * Rapid implementation * Compliance with data collection requirements * Reduced development overhead ### Implementing the hosted flow 1. Obtain the Straddle Embed script from your dashboard 2. Include the script in your application 3. Initialize the Straddle Embed component with your configuration 4. Handle the callback with the onboarding result ## Compliance considerations You don't have to worry about onboarding compliance, KYC, AML, or any other regulations. Straddle handles all compliance requirements for you. Seriously. ## Testing and sandbox environment Straddle provides a sandbox environment for testing your integration: * Use test API keys for all sandbox operations * Simulate various onboarding scenarios and edge cases * Test webhook integrations with simulated events Thoroughly test your integration in the sandbox environment before going live. ## Going live Once you've completed testing and are ready to go live, follow these steps: Review and update your integration based on sandbox testing results. Obtain production API keys from the Straddle dashboard. Update your integration to use production endpoints and keys. Implement a phased rollout to minimize potential issues. Monitor your integration closely during the initial live period. ## Support and resources For additional assistance and resources: For integration assistance, contact [support@straddle.com](mailto:support@straddle.com). Access the latest technical information: * [API Documentation](https://docs.straddle.com/api-reference) * [Changelog](https://docs.straddle.com/changelog/updates/2026) * [Developer Blog](https://straddle.com/blog) # Organizations: group multiple accounts Source: https://docs.straddle.com/guides/embed/organizations Use organizations to group related Straddle accounts under a single umbrella for businesses with multiple departments, brands, or legal entities. Organizations are a powerful feature in Straddle that allow you to manage multiple accounts under a single umbrella. This hierarchical structure is particularly useful for businesses with complex operations, multiple departments, or those managing payments for various clients. ## Understanding organizations Think of an organization as the parent entity that can house multiple Straddle accounts. This structure offers several advantages: 1. **Centralized Management**: Oversee all your accounts from a single dashboard. 2. **Streamlined Onboarding**: Easily create new accounts using existing KYC information. 3. **Consolidated Reporting**: Get a holistic view of your business operations across all accounts. 4. **Unified Team Management**: Manage user roles and permissions at the organization level. 5. **Cross-Account Search**: Quickly find information across all your accounts. ## Creating an organization To start leveraging the power of organizations, you first need to create one. Use the Create Organization endpoint to set up a new organization in Straddle. ### Attributes When creating an organization, you can specify the following attributes: | Field | Type | Description | | - | - | - | | name | string | The name of your organization. Choose something recognizable and unique. | | metadata | object | Additional key-value pairs for storing extra information about the organization. | | external\_id | string | Your own unique identifier for the organization, useful for cross-referencing. | ### Example request Here's how you might create a new organization: ```bash theme={null} curl https://api.straddle.com/v1/organizations \ -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Global Tech Solutions", "metadata": { "industry": "Information Technology", "size": "Enterprise", "headquarters": "San Francisco" }, "external_id": "GTS-2023" }' ``` ```javascript theme={null} async function createOrganization() { const res = await fetch('https://api.straddle.com/v1/organizations', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Global Tech Solutions', metadata: { industry: 'Information Technology', size: 'Enterprise', headquarters: 'San Francisco' }, external_id: 'GTS-2023' }) }) const json = await res.json() console.log(json) } ``` ### Response Upon successful creation, Straddle responds with the details of the newly created organization: | Field | Type | Description | | - | - | - | | id | string | Straddle's unique identifier for the organization. | | name | string | The name you provided for the organization. | | external\_id | string | Your provided unique identifier for the organization. | | metadata | object | The additional key-value pairs you provided. | ## Managing organizations Once you've created an organization, you can start adding accounts to it, managing team access, and leveraging its capabilities for streamlined operations. ### Listing organizations To view all the organizations you've created, use the List Organizations endpoint. This is particularly useful when managing multiple organizations or when you need to retrieve a specific organization's ID. #### Query parameters | Parameter | Type | Description | | - | - | - | | name | string | Filter organizations by name (supports partial matching). | | external\_id | string | Filter organizations by their external ID. | | page\_number | integer | The page number for paginated results (default: 1). | | page\_size | integer | Number of results per page (default: 100, max: 1000). | | sort\_by | string | Field to sort by (default: 'id'). | | sort\_order | string | Sort order: 'asc' or 'desc' (default: 'asc'). | #### Example request Here's how you might list your organizations: ```bash theme={null} curl https://api.straddle.com/v1/organizations?page_size=5&sort_by=name \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript theme={null} async function listOrganizations() { const url = new URL('https://api.straddle.com/v1/organizations') const res = await fetch('https://api.straddle.com/v1/organizations?page_size=5&sort_by=name', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }) const json = await res.json() console.log(json) } ``` ## Best practices When working with organizations in Straddle, consider the following best practices: Choose clear, descriptive names for your clients' organizations. This will make it easier to manage them as your use of Straddle grows. Take advantage of the metadata field to store additional information about the organizations. This can be invaluable for internal categorization or integration with other systems. If you choose to use external IDs, we strongly recommend the usage of UUIDs. This will help maintain clarity when cross-referencing between Straddle and your own systems. Periodically review your organizations and their associated accounts. This can help ensure that your Straddle setup continues to align with the business structure. ## Next steps Now that you understand how to create and manage organizations, you're ready to start leveraging their power in Straddle. Here are some next steps you might consider: Start adding accounts to your organization to take full advantage of Straddle's hierarchical structure. Learn how to create and manage accounts under your organization for streamlined operations. Discover how to use Straddle's reporting features to gain insights across all accounts in your organization. Learn how to keep your account details up-to-date as your business evolves. # Straddle Embed for platforms overview Source: https://docs.straddle.com/guides/embed/overview An overview of Straddle Embed for marketplaces and SaaS platforms, including embedded accounts, onboarding, capabilities, and bank-payment infrastructure. ## What is Straddle Embed? Straddle Embed is a purpose-built solution that enables software providers, marketplaces, and payment facilitators to easily integrate Straddle's open banking payment capabilities into their own offerings. With Straddle Embed, platforms can extend and monetize payments infrastructure with all the benefits of a "PayFac" program, but without the regulatory headaches or liabilities. Straddle Embed allows platforms to focus on building compelling software while Straddle manages payments, compliance, and risk. Embed integrators carry no payment liability or flow of funds exposure. Leverage Straddle Embed to enhance your platform: * **Massive Scale:** Extend all core Straddle features through a single, platform-level integration. * **Competitive Edge:** Differentiate with next-generation payment capabilities for platform stickiness. * **Instant Merchant Onboarding:** Get new merchants transacting in minutes, document-free. * **Monetization:** Benefit from a flexible revenue sharing model (up to 60% of monthly earnings). Straddle Embed powers diverse platforms with specific payment needs: * **SaaS Platforms:** Embed subscription billing, automated invoicing, and varied payment options for your clients. * **Marketplaces:** Integrate secure buyer-to-seller payments, escrow, and automated commission payouts. * **Payment Facilitators:** Offer open-banking, reduced transaction costs, and faster settlements. * **Enterprise Solutions:** Embed customizable payment flows, ERP integrations, and high-volume transaction handling. Designed from the ground up for embedded scenarios: * **Multi-Tenant Design:** Natively manage and isolate multiple merchants under your single platform account. * **Flexible Authentication & Context:** Supports platform-level and account-specific API interactions, with API responses automatically including relevant account/platform context. * **Webhooks:** Receive real-time event notifications at both platform and individual merchant levels. ## Platform models Straddle Embed supports two distinct platform models, each with unique customer management approaches: Vertical-specific software with embedded payment capabilities Platforms facilitating transactions between users and sellers/vendors ## SaaS platform model ### Overview A SaaS platform provides specialized software to businesses in specific industries. In this model, end users do not register with the SaaS platform itself. They are customers of the businesses that use the SaaS. When payments occur, they happen through the business's interface, with the SaaS platform processing transactions in the background. ### Key characteristics * **Customer Relationship**: End users are customers of the SaaS client (account), not the SaaS platform itself * **Customer Management**: 1:1 relationship between customers and accounts * **Branding**: The business's brand is front-and-center, platform operates behind the scenes * **User Experience**: End users interact with payment forms embedded in the business's workflow * **Payment Flow**: Directed through the business's branded interface ### Typical user journey 1. **Interaction with a Business**: The end user is a customer of a business that uses your SaaS platform 2. **Payment Initiation**: When payment is needed, the user sees a payment form within the business's interface 3. **Behind-the-Scenes Processing**: Your platform handles the payment flow and compliance checks 4. **Account-Specific Experience**: The customer's profile exists within the context of that specific business ### Use cases * **Practice Management Software**: Medical offices, law firms, or accounting practices * **Loan Servicing Platforms**: Lenders offering payment options to borrowers * **Subscription Billing Solutions**: SaaS companies managing recurring payments * **Invoice Management Systems**: Businesses sending invoices to their customers ## Marketplace platform model ### Overview In a marketplace model, end users (customers) register directly with your platform and can interact with multiple sellers (accounts) within your ecosystem. The marketplace facilitates transactions between parties and maintains centralized customer profiles. ### Key characteristics * **Customer Relationship**: End users register directly with the marketplace platform * **Customer Management**: One:Many relationship - platform-level customers can transact with multiple accounts * **Branding**: The marketplace brand is prominent throughout the experience * **User Experience**: Centralized profile, payment methods, and transaction history * **Payment Flow**: All transactions occur through the marketplace's ecosystem ### Typical user journey 1. **Platform Registration**: The end user creates a profile directly with your marketplace 2. **Identity & Payment Setup**: The user provides identity information and connects payment methods 3. **Browsing & Transactions**: The user interacts with multiple sellers, merchants, or vendors from your application 4. **Centralized Experience**: All transaction history, communication, and dispute resolution happen through the marketplace ### Use cases * **E-commerce Marketplaces**: Platforms where multiple merchants sell to consumers * **Wallets**: Tap-to-pay or stored value wallets where customers can interact with any seller or vendor connected to the wallet * **Service Marketplaces**: Platforms connecting service providers with clients * **Rental Marketplaces**: Property or equipment rental platforms * **Gig Economy Platforms**: Connecting freelancers with those needing services ## Key differences between models | Aspect | SaaS Platform | Marketplace Platform | | - | - | - | | User Registration | No direct profile with platform; user is a customer of the SaaS client | Customer creates a direct profile on the marketplace | | Customer Model | 1:1 (customers tied to specific accounts) | Many:Many (platform customers can transact with multiple accounts) | | User Profile | Maintained by the business, not the platform | Centralized on the marketplace (profile, payment methods, history) | | Payment Flow | Embedded in business workflow | Centralized within marketplace ecosystem | | Branding | Business brand is front-and-center | Marketplace brand is front-and-center | | Compliance/KYC | Managed through the business, typically invisible to user | Per marketplace requirements, managed directly | | Revenue Model | Subscription + transaction fees paid by businesses | Marketplace fees + transaction fees | | Ongoing Engagement | Users typically interact only when making payments | Users return to marketplace for future needs | ## Generate revenue with Straddle Embed ### For SaaS platforms * **Embedded Payments**: Add payment capabilities without building payment infrastructure * **Increased Revenue**: Generate additional revenue through transaction fees * **Enhanced Value**: Provide a more complete solution to your business clients * **Reduced Complexity**: No need to handle payment compliance or risk management * **White-labeled Experience**: Keep your platform in the background while highlighting your clients' brands ### For marketplace platforms * **Centralized Customer Management**: Create and manage customers at the platform level * **Seamless Customer Experience**: Allow customers to transact with multiple sellers without re-registering * **Reduced Friction**: Simplify payment flows for repeat transactions * **Unified Profile**: Maintain payment methods, preferences, and history in one place * **Enhanced Control**: Manage compliance, disputes, and refunds centrally ## Choosing the right model Consider these factors when deciding between SaaS and Marketplace models: * **Business Relationship**: Who owns the relationship with the end user? * **Transaction Flow**: Do you need a central payment hub or embedded payment capabilities? * **User Experience**: Should users maintain one profile or separate profiles with each business? * **Branding Strategy**: Should your platform brand be prominent or in the background? - End users are primarily customers of your clients - Your platform provides industry-specific software - Payments should be embedded into business workflows - Client branding should be prominent during payment flows * End users register directly with your platform * You facilitate transactions between buyers and sellers * You need centralized control of payments * Platform branding should be consistent across transactions ## Getting started with Straddle Embed Ready to enhance your platform with Straddle Embed? Here's how to get started: 1. [Register for Straddle Sandbox access](https://dashboard.straddle.com/) 2. Schedule a consultation with our platform specialists 3. Define your platform model and customer management approach 4. Work with our team to design your ideal payment experience 5. Begin integration with our comprehensive API documentation For additional support or questions, [contact our support team](mailto:support@straddle.com). # Straddle Embed React component Source: https://docs.straddle.com/guides/embed/react-onboarding Integrate and customize the Straddle Embed onboarding form in your React application, including theming, callbacks, and merchant verification flows. The Embed component provides a seamless way to integrate Straddle forms into your React application. This guide covers everything you need to know about implementing and customizing the component. This component automatically handles responsive layouts and dynamic height adjustment, making it ideal for a variety of application layouts and screen sizes. ## Key features Flexible width options from narrow to full-width to suit any layout needs Automatically adjusts height based on form content Built-in TypeScript definitions for reliable type checking Built-in error handling with customizable fallback options ## Installation and setup Ensure React is installed in your project. The Straddle Embed Component is compatible with React 16.8 and above. Copy the `StraddleEmbedComponent.tsx` file into your project's component directory. Import and implement the component in your application: ```tsx theme={null} import React from 'react'; import StraddleEmbedComponent from './path/to/StraddleEmbedComponent'; function MyComponent() { return ( ); } ``` ## Component props Your unique Straddle platform identifier. This is used to associate the embedded form with your specific account or configuration. A string value representing the Straddle environment in which form submissions are created (e.g., `production`, `sandbox`). Controls the component's maximum width. Available options: Sets maximum width to 384px (max-w-sm) Sets maximum width to 768px (max-w-3xl) Sets maximum width to 1024px (max-w-5xl) Uses 100% of container width Removes max-width constraint ## Implementation examples ### Basic usage ```tsx Basic theme={null} import React from 'react'; import StraddleEmbedComponent from './StraddleEmbedComponent'; function MyComponent() { return ( ); } ``` ```tsx With Custom Width theme={null} import React from 'react'; import StraddleEmbedComponent from './StraddleEmbedComponent'; function MyComponent() { return ( ); } ``` ### Responsive implementation ```tsx Responsive Example theme={null} import React, { useState, useEffect } from 'react'; import StraddleEmbedComponent from './StraddleEmbedComponent'; function ResponsiveStraddleEmbed() { const [maxWidth, setMaxWidth] = useState('full'); useEffect(() => { const mediaQuery = window.matchMedia('(min-width: 768px)'); const handleMediaQueryChange = (e) => { setMaxWidth(e.matches ? 'medium' : 'full'); }; mediaQuery.addListener(handleMediaQueryChange); handleMediaQueryChange(mediaQuery); return () => mediaQuery.removeListener(handleMediaQueryChange); }, []); return ( ); } ``` ## Configuration details ### URL parameters The Straddle embed URL includes several preconfigured parameters that control the form's appearance and behavior. These parameters are automatically set in the component for optimal integration. The `env` value is not injected into the URL, but is instead provided as a separate data attribute, making it accessible to the embedded form internally. When set to 1, aligns all content to the left of the container When set to 1, removes the default form title When set to 1, makes the form background transparent to match your application When set to 1, enables automatic height adjustment based on form content When set to 1, optimizes the form for embedded display ### Using the `env` prop The `env` prop allows you to indicate whether the embedded Straddle form should create a test account (in your platform's sandbox environment) or a real, production-level account. This is particularly useful when you're testing webhook integrations, trialing new features, or verifying payment flows before going live. **How It Works:** * **Sandbox Environment:**\ When `env` is set to a value indicating a sandbox or test environment (e.g., `env="sandbox"`), the embedded form creates new accounts in your sandbox environment. This ensures you can safely experiment, test your integrations, and verify webhook responses without impacting live data or existing real accounts. * **Production Environment:**\ When `env` is set to `production`, the embedded form operates against your real, production-level environment. Accounts created, data submitted, and webhooks triggered from this embedded form reflect actual usage scenarios and should be treated as live, customer-facing transactions. **No Direct URL Changes:**\ The `env` value is not appended to the Straddle form URL. Instead, it's passed as a data attribute on the iframe (i.e., `env`), allowing the form itself (within the iframe) to interpret and act upon the environment setting. This ensures that the same URL can be used consistently, while the underlying logic—such as which database endpoints or webhook routes to invoke—is dynamically adjusted based on `env`. **Recommended Usage:** * Use `env="sandbox"` whenever you're testing new integrations, verifying that your webhook listeners work correctly, or experimenting with new features. * Switch to `env="production"` only when you're ready for real-world usage, ensuring that account creations, messages, and webhooks are fully integrated into your live environment. ### Dynamic height behavior The component implements a sophisticated height management system that combines fixed minimum heights with dynamic content adjustment. The dynamic height functionality works through two mechanisms: 1. The `dynamicHeight=1` URL parameter enables the embed to communicate its content height. 2. A minimum height of 500px is enforced via inline styles to prevent layout shifts during loading. Modifying the minimum height may cause layout instability during the initial load. The default 500px value is recommended for most use cases. ### TypeScript integration The component includes comprehensive TypeScript definitions for enhanced development experience: ```typescript Type Definitions theme={null} interface StraddleEmbedComponentProps { platformId: string; env: string; // Now included as a required prop maxWidth?: 'narrow' | 'medium' | 'wide' | 'full' | 'auto'; } ``` ```typescript Usage with Types theme={null} import React from 'react'; import StraddleEmbedComponent from './StraddleEmbedComponent'; const MyComponent: React.FC = () => { return ( ); }; ``` ### Script loading and error handling The component implements robust script loading with automatic fallbacks: Attempts to load the Straddle embed script from '[https://forms.straddle.com/embed.js](https://forms.straddle.com/embed.js)' If the script fails to load or execute properly, the component falls back to direct iframe source setting Implements comprehensive error handling for both script loading and execution failures ```typescript Error Handling Implementation theme={null} const handleScriptError = () => { console.error('Failed to load the Straddle embed script.') loadEmbeds() } if (!existingScript) { const script = document.createElement('script') script.src = embedScriptSrc script.async = true script.onload = loadEmbeds script.onerror = handleScriptError document.body.appendChild(script) } ``` ## Advanced usage ### Error handling ```tsx Error Boundary theme={null} import React from 'react'; import ErrorBoundary from './ErrorBoundary'; import StraddleEmbedComponent from './StraddleEmbedComponent'; function MyComponent() { return ( Error loading Straddle form}> ); } ``` ## Best practices While your `platformId` is not secret, it is recommended to store it in environment variables or a secure configuration management system. Use the `env` prop to indicate the deployment environment (such as production, staging, or sandbox) to the embedded form. The form can then read this value and adjust its behavior or display accordingly. Choose the appropriate maxWidth based on your layout requirements. Use 'medium' for standard forms and 'full' for responsive layouts. Implement error boundaries to gracefully handle any loading or rendering issues with the embed component. The component uses lazy loading by default. Ensure the container has sufficient space to prevent layout shifts during loading. ### Custom component integration The Straddle Embed Component can be wrapped with custom components to extend its functionality: ```tsx Custom Container theme={null} import React from 'react'; import StraddleEmbedComponent from './StraddleEmbedComponent'; const CustomStraddleContainer: React.FC = () => { return (

Account Setup

Need help? Contact support
); }; ``` ```tsx With Loading State theme={null} import React, { useState } from 'react'; import StraddleEmbedComponent from './StraddleEmbedComponent'; const LoadingAwareStraddle: React.FC = () => { const [isLoading, setIsLoading] = useState(true); return (
{isLoading && } setIsLoading(false)} />
); }; ```
### Styling integration The component uses Tailwind CSS classes for layout management. Here's how different width options map to Tailwind classes: Uses `max-w-sm` (384px) Uses `max-w-3xl` (768px) Uses `max-w-5xl` (1024px) Uses `w-full` (100%) No width constraint The component's container uses `flex justify-center w-full` to ensure proper centering and responsive behavior. ### Performance considerations The embed script is loaded asynchronously to prevent blocking page rendering. The component uses a single-instance pattern to avoid loading multiple copies of the script. The component properly cleans up event listeners and script references on unmount to prevent memory leaks. The minimum height setting helps prevent Cumulative Layout Shift (CLS) during form loading. ## Troubleshooting If you encounter issues with the embed component, verify these common points: Ensure the Straddle embed script ([https://forms.straddle.com/embed.js](https://forms.straddle.com/embed.js)) is loading correctly in your network tab. Verify your `platformId` and `env` values are correct and properly formatted. The `env` prop should match the environment context you intend the form to operate within. Check that the parent container provides adequate space for the embed to render properly. Verify there are no network issues preventing the iframe content from loading. ## Related resources Complete API reference for Embed Get started with implementation examples Test your implementation in our sandbox environment Join our Slack community for additional help # Manage account representatives Source: https://docs.straddle.com/guides/embed/representatives Add and verify business representatives, beneficial owners, and authorized signers for KYB compliance on your embedded Straddle accounts. Representatives are individuals who have legal authority or significant responsibility within a business entity associated with a Straddle account. Understanding how to manage representatives is crucial for maintaining compliance and ensuring smooth account operations. ## Understanding representatives Representatives in Straddle serve several key purposes: 1. **Legal Compliance**: They fulfill regulatory requirements for identifying individuals with control over business accounts 2. **Account Management**: They can be authorized to make changes to the account or view sensitive information 3. **Risk Assessment**: They help Straddle evaluate the risk profile of an account 4. **Communication Channel**: They serve as points of contact for important account-related communications Add multiple representatives to a single account Specify different roles and responsibilities for each representative Update representative information as needed programmatically Verified representative information is required to meet FinCEN compliance A representative profile must be created for at least one individual with "control"-- think a CFO, CTO, or Director -- and every individual with >25% ownership. An account can have from 1-5 representatives associated with it. ## Key considerations Ensure you have a robust process for collecting accurate representative information from your clients. Communicate to your clients why representative information is crucial for account setup and compliance. Implement logic to handle representative status changes, especially if a representative is rejected during verification. Offer easy ways for clients to update their representative information when needed. ## Creating a representative To add a representative to an account, use the Create Representative endpoint. You must add at least one representative where `relationship.control` = `true` to an account before it can be onboarded. ### Attributes When creating a representative, you can specify the following attributes: | Field | Type | Description | | - | - | - | | account\_id | string | The unique identifier of the account this representative is associated with. | | first\_name | string | The first name of the representative. | | last\_name | string | The last name of the representative. | | dob | string | Date of birth for the representative in ISO 8601 format (YYYY-MM-DD). | | ssn\_last4 | string | The last 4 digits of the representative's Social Security Number. | | email | string | The company email address of the representative. | | mobile\_number | string | The mobile phone number of the representative. | | relationship | object | Describes the representative's relationship to the account. | | relationship.primary | boolean | Whether this is the primary representative for the account. | | relationship.control | boolean | Whether the representative has significant control over the business. | | relationship.owner | boolean | Whether the representative is an owner of the business. | | relationship.percent\_ownership | number | The percentage of ownership, if the representative is an owner. | | relationship.title | string | The job title of the representative. | | external\_id | string | Your own unique identifier for the representative. | ### Example request Here's how you might create a new representative: ```bash theme={null} curl https://api.straddle.com/v1/representatives \ -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "account_id": "acct_1234567890abcdef", "first_name": "Jane", "last_name": "Doe", "dob": "1980-01-15", "ssn_last4": "1234", "email": "jane.doe@techinnovators.com", "mobile_number": "+1 (555) 123-4567", "relationship": { "primary": true, "control": true, "owner": true, "percent_ownership": 51, "title": "CEO" }, "external_id": "rep_jd001" }' ``` ```javascript theme={null} async function createRepresentative() { const res = await fetch('https://api.straddle.com/v1/representatives', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ account_id: 'acct_1234567890abcdef', first_name: 'Jane', last_name: 'Doe', dob: '1980-01-15', ssn_last4: '1234', email: 'jane.doe@techinnovators.com', mobile_number: '+1 (555) 123-4567', relationship: { primary: true, control: true, owner: true, percent_ownership: 51, title: 'CEO' }, external_id: 'rep_jd001' }) }) const json = await res.json() console.log(json) } ``` ### Representative statuses Representatives, like accounts, have different statuses that reflect their current state in the system. Understanding these statuses is crucial for managing representatives effectively. Possible values: * `created`: Initial status when a representative is first added * `onboarding`: The representative is going through the verification process * `active`: The representative has been verified and is active * `rejected`: The representative has failed verification * `inactive`: The representative has been deactivated ### Status details The `status_detail` object provides more granular information about the representative's current status: Possible values: * `unverified`: Initial state, pending verification * `in_review`: Representative is being reviewed * `pending`: Waiting for additional information * `stuck`: Issues in the verification process * `verified`: Successfully verified * `failed_verification`: Verification process failed * `disabled`: Representative has been disabled Always "watchtower", Straddle's compliance monitoring system. A specific code related to the status reason. A human-readable message providing more context about the current status. ## Update a representative During the onboarding process, you may need to update representative information for various reasons. However, the ability to update a representative depends on their current status. Understanding when and why you might need to update a representative is crucial for smooth account onboarding. ### When can you update a representative? You can update a representative when their status is: * Created: Full updates allowed * Onboarding: Most updates allowed * Active: Limited updates allowed You cannot update a representative when their status is: * Rejected: Updates not allowed * Inactive: Updates not allowed For representatives in these statuses, contact Straddle support for assistance. ### Why update a representative? There are several reasons why you might need to update a representative during the onboarding process: 1. **Correction of Errors**: Initial submission might contain mistakes that need to be rectified. 2. **Additional Information Required**: Straddle's verification process might request more details. 3. **Change in Circumstances**: The representative's role or contact information might change during onboarding. 4. **Compliance Requirements**: Additional information might be needed to meet specific regulatory requirements. ### What can be updated? Depending on the representative's status, different fields can be updated: All fields can be updated when the status is 'created'. Most fields can be updated, but changes might restart parts of the verification process. Only non-critical information (like contact details) can typically be updated without triggering re-verification. ### Example: Updating a representative Here's an example of updating a representative's information during the onboarding process: ```bash theme={null} curl https://api.straddle.com/v1/representatives/rep_1234567890abcdef \ -X PUT \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "mobile_number": "+1 (555) 987-6543", "relationship": { "title": "CFO", "percent_ownership": 25 } }' ``` ```javascript theme={null} async function updateRepresentative() { const res = await fetch('https://api.straddle.com/v1/representatives/rep_1234567890abcdef', { method: 'PUT', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ mobile_number: '+1 (555) 987-6543', relationship: { title: 'CFO', percent_ownership: 25 } }) }) const json = await res.json() console.log(json) } ``` ### Best practices for updating representatives Follow these best practices when updating representative information during onboarding: 1. **Check Current Status**: Always verify the representative's current status before attempting an update. 2. **Minimize Changes**: Only update information that is absolutely necessary to avoid delays in the verification process. 3. **Provide Explanations**: When making significant changes, consider adding a note in the metadata to explain the reason for the update. 4. **Monitor Status Changes**: After an update, closely monitor the representative's status for any changes or additional requirements. 5. **Prepare for Re-verification**: Be aware that certain updates might trigger a re-verification process, potentially extending the onboarding timeline. Updating critical information (like name or date of birth) for a representative in 'active' status may trigger a re-verification process. Only do this if absolutely necessary and be prepared for potential delays. ### Handling update restrictions If you attempt to update a representative in a non-updateable status (rejected or inactive), you'll receive an error response. In these cases: 1. For **rejected** status: Review the rejection reason in the status\_detail. You may need to create a new representative instead of updating the existing one. 2. For **inactive** status: Contact Straddle support for guidance on how to proceed, as reactivation might be possible in some cases. Remember, the ability to update representatives is designed to ensure accuracy of information during the onboarding process while maintaining the integrity of Straddle's verification procedures. Always prioritize providing accurate information from the start to minimize the need for updates and potential delays. ## Lookup a representative To view the details of a specific representative, use the Get Representative endpoint. #### Example request ```bash theme={null} curl https://api.straddle.com/v1/representatives/rep_1234567890abcdef \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript theme={null} async function getRepresentative() { const res = await fetch('https://api.straddle.com/v1/representatives/rep_1234567890abcdef', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }) const json = await res.json() console.log(json) } ``` ## Best practices When working with representatives in Straddle, consider the following best practices: Always verify the accuracy of representative information before submission. Incorrect details can lead to verification issues. Consider adding multiple representatives to ensure continuity of account access and management. Update representative information promptly when changes occur to maintain compliance and accurate records. Handle representative personal information with care, adhering to relevant data protection regulations. ## For platforms: Managing client representatives If you're a platform creating accounts on behalf of your clients, here are some key considerations for managing representatives: Ensure you have a robust process for collecting accurate representative information from your clients. Communicate to your clients why representative information is crucial for account setup and compliance. Implement logic to handle representative status changes, especially if a representative is rejected during verification. Offer easy ways for clients to update their representative information when needed. Remember, at least one representative must be added to an account before it can be onboarded. Ensure you add representatives promptly after account creation to avoid delays in the onboarding process. # Straddle platform glossary Source: https://docs.straddle.com/guides/glossary Definitions of key terms and concepts used across Straddle, including ACH, paykeys, customers, charges, payouts, funding events, and identity verification. This glossary is comprehensive and *very* detailed, and is designed to serve as a valuable reference during your implementation of Straddle's services. Don't go crazy memorizing all of these, but do refer back to them as needed. ## A ### ACH (automated clearing house) An electronic network for financial transactions in the United States, used by Straddle for processing certain types of bank transfers. ### Account A business entity that has entered into a contractual relationship with Straddle to use its services directly. Accounts can access the Straddle API Sandbox upon creation and need to complete an onboarding process for production access. ### Account status The current state of a Straddle account, which can be one of: `created`, `onboarding`, `active`, `rejected`, or `inactive`. ### Account-to-account (A2A) payments Transactions that move money directly from one bank account to another. Straddle orchestrates A2A money movement via multiple payment rails so you don't have to worry. ### Address risk A component of Identity that provides a risk score for physical addresses. ### Adverse media screening A component of Identity that identifies individuals associated with news items related to financial crimes. ### AML (anti-money laundering) Regulations and procedures that Straddle helps you comply with to prevent criminals from disguising illegally obtained funds as legitimate income. ### API (application programming interface) A set of protocols and tools for building software applications, specifically referring to Straddle's API. The Straddle API allows developers to integrate payment and identity verification features into their applications. ### API key A unique identifier used to authenticate requests to the Straddle API. API keys should be kept secure and not shared publicly. ### API version The specific version of the Straddle API being used, which determines the available features and endpoints. ### Authentication The process of verifying the identity of a user or system making requests to the Straddle API. Straddle uses Bearer tokens for API authentication. ## B ### Balance check A feature in Straddle's platform that verifies the available balance in a customer's account before initiating a charge. This helps prevent failed payments due to insufficient funds. ### Bank account verification The process of confirming that a bank account is valid and belongs to the stated owner. Straddle offers multiple methods for bank account verification, including API-based verification and open banking connections. ### Bearer token A type of access token used for authentication in the Straddle API. ### Bridge Straddle's comprehensive suite of account connectivity endpoints that facilitate secure connections between users and their financial accounts. Bridge includes: * A drop-in open banking widget * Support for third-party tokens (e.g., Plaid, MX) * API-based bank account verification ### Bridge token A JWT (JSON Web Token) used in the Straddle Bridge widget for secure account connectivity. Bridge tokens are generated using the `/v1/bridge/initialize` endpoint. ### Bridge widget A drop-in user interface component provided by Straddle for easy integration of bank account connectivity features. The Bridge Widget is a hosted UI component that you can embed on your website to allow customers to connect their bank accounts to your platform. ### Business profile A set of information about an account on the Straddle platform, including details such as legal name, business name, website, description, tax ID, address, and industry information. ## C ### Capability A specific feature or permission granted to an account on the Straddle platform. Capabilities include `payment_types`, `customer_types`, and `consent_types`. ### Capability request A formal request to enable a specific capability for an account on the Straddle platform. ### Charge A type of payment transaction where money is debited from a Customer. Charges are created using the `/v1/charges` endpoint. ### Compliance profile A set of information in the Straddle API request when creating a Customer that triggers fully-compliant KYC validation. ### Consent type The method by which a customer provides authorization for a transaction. Straddle supports two consent types: `internet` and `signed`. ### Correlation ID An optional client-generated identifier passed in the request headers to trace and debug a series of related API requests. ### Correlation score A measure of the relationship strength between different elements of provided personally identifiable information (PII). ### Create charge The API endpoint and process for initiating a new charge transaction. ### Create payout The API endpoint and process for initiating a new payout transaction. ### Currency The monetary unit used for transactions on the Straddle platform. ### Customer An individual or business involved in a payment transaction with your business. All customers are automatically screened for fraud and watchlist compliance when they are created. The customer object is used to: * Manage fraud and compliance * Generate paykeys * Relate payment activity * Send notifications ### Customer identification program (CIP) A government-mandated regulation that Straddle's KYC process complies with. Straddle Identity keeps you compliant with CIP requirements by: * Screening customers for fraud * Performing (optional) KYB and KYC * Matching against watchlist databases * Enrolling in ongoing watchlist monitoring ### Customer review An endpoint in the Straddle API that allows you to review a customer's identity results. ### Customer status The current state of a customer in the Straddle system, which can be one of: `pending`, `review`, `verified`, `inactive`, or `rejected`. ### Customer type The classification of a customer as either an individual or a business. This determines the type of information required for verification and the available features. ## D ### Dashboard The web-based user interface provided by Straddle for account setup, activity reporting, customer management, and more. ### Decision engine The core component of Straddle's Identity that provides automated decisioning on fraud, synthetic ID, and PII matching. ### Deposit A type of funding event where money is sent from Straddle to your business bank account for the settlement of charges. ### Device info Information about the device used by a customer during a transaction. ## E ### Email risk A component of Identity that provides a risk score for email addresses. ### Embed A product offering by Straddle that enables deeply integrated payment infrastructure for platforms, marketplaces, and other PSP/PayFac providers. Embed simplifies the process of integrating bank payments and managing complex money movement scenarios within an app or service. ### Error response A standardized format for API responses when an error occurs. ### External ID A unique identifier provided by the integrating application for cross-referencing purposes between Straddle and an external system. ## F ### Fraud score A score that assesses the risk of identity fraud associated with a transaction. ### Funding event Represents the movement of money between Straddle and an Account. Funding events are automatically generated as part of a payment and cannot be created directly via the API. ### Funding event type The classification of a funding event, which can be `charge deposit`, `charge reversal`, `payout return`, or `payout withdrawal`. ### Funding time The time that it takes for a funding event to complete. Unlike other providers, Straddle initiates funding events within 24 hours. ## G ### Global watchlist screening Straddle's process for identifying risk by matching entities against sanctions and enforcement lists. ## H ### HTTP status code A standard code returned with an API response to indicate the outcome of the request. ## I ### Identity velocity A factor considered in Identity that monitors the frequency and recency of identity usage. ### Identity verification The process of confirming a customer's identity. Straddle uses a combination of techniques to verify customer identities. ### Identity-linked payment Straddle's core concept of connecting verified customer identities directly to payment methods. Paykeys are a new kind of payment token that contain both a customer's identity and payment information. ### Industry The business sector in which an Account operates. ## K ### Know your business (KYB) The process of verifying the identity and suitability of business customers. ### Know your customer (KYC) Straddle's process of verifying the identity and suitability of customers. This process helps prevent fraud and ensures compliance with regulatory requirements. ### KYC field validations Comprehensive checks performed by Straddle on provided PII fields. ## L ### Linked bank account A bank account that has been connected to a Straddle Account. Funding events, like deposits and withdrawals, are transfers from Straddle to the linked bank account. ## M ### Metadata User-defined key-value pairs that can be attached to various objects in the Straddle system. Metadata is useful for storing additional information about an object in a structured format. ## N ### Network alerts Notifications generated by Straddle's consortium partners related to potential risks related to a Customer or Payment. ## O ### OAuth An open standard for access delegation, used in Straddle's authentication process. ### OFAC SDN List One of the key watchlists that Straddle screens against as part of its Global Watchlist Screening process. ### Open banking A banking practice that provides third-party financial service providers open access to consumer banking, transaction, and other financial data. ### Organization A centralized entity in Straddle that allows management of multiple accounts. Organizations provide features such as centralized dashboard, streamlined account onboarding and user management, and consolidated reporting. ## P ### Pagination The practice of dividing a large set of results into smaller, manageable "pages" in API responses. ### Pay by Bank Straddle's unified API flow for bank payments. Pay by Bank combines identity verification, open banking, and money movement into a single API. ### Paykey A secure token that links a verified customer identity to a specific payment method. Paykeys are a core component of Straddle's identity-linked payment system. ### Paykey source The origin of a Paykey, which can be a bank account, Straddle, or a third-party provider like Plaid or MX. ### Paykey status The current state of a Paykey in the Straddle system, which can be `pending`, `active`, `inactive`, or `rejected`. ### Payment A transaction between a Customer and a business (Account) using Straddle's payment services. Straddle supports two types of payments: `charge` and `payout`. ### Payment date The date on which a payment is scheduled to occur. ### Payment rail The specific method or network used to process a payment, such as ACH or RTP. ### Payment status The current state of a payment transaction, which can include `created`, `pending`, `paid`, `failed`, or `cancelled`. ### Payout A type of payment transaction where money is sent to a customer. ### Phone risk A component of Straddle's risk assessment that provides a risk score for phone numbers. ### Politically exposed person (PEP) screening A part of Straddle's watchlist screening process to identify individuals who hold prominent public positions. ## R ### Rate limiting Restrictions on the number of API requests that can be made within a given time period. ### Real-time monitoring Straddle's continuous process of monitoring existing customers for changes in watchlist status. ### Representative An individual who has legal authority or significant responsibility within a business Account on the Straddle platform. ### Request example A sample API request provided in the documentation to illustrate proper usage. ### Request ID An optional client generated header value that is returned in the API response. The request ID can be used to trace and debug individual API requests. ### Risk score A numerical value assigned by Straddle's system to indicate potential risk associated with a transaction or customer. ## S ### Sandbox A testing environment that mimics the live Straddle platform, allowing developers to test API integrations without affecting real accounts or transactions. The Sandbox is available to all Straddle accounts via the url `https://sandbox.straddle.com`. ### Sanctions and enforcements screening Straddle's process of screening consumers and businesses during onboarding against various sanctions lists. ### Status details Additional information about the current status of an object in the Straddle system. ### Status history A record of status changes for an object over time. ### Straddle Account ID A unique identifier for a Straddle account. This is the primary identifier for an account in the Straddle system. This value can be used by Platforms to originate API requests to Straddle on behalf of an Account by including the header `X-Straddle-Account-Id`. ### Straddle Identity An all-in-one identity verification system that provides a risk score for physical addresses, email risk, phone risk, and more. Identity uses a combination of machine learning, big data, and predictive analytics to accurately verify identities and prevent fraud. ### Support channels The various methods provided by a business during Account onboarding for customer support, such as email, phone, or chat. ### Synthetic ID detection Custom models trained with consortium data to detect fake and randomized synthetic patterns. Produces real-time, actionable risk scores and reason codes, with 90% auto-capture in the riskiest 3% of users. ### Synthetic identity risk score A score that predicts the probability that provided PII corresponds to a fictitious person. ## T ### Terms of service The agreement that users must accept to use the Straddle platform. ### Third-party fraud Also known as identity fraud, where an imposter uses a real person's information for financial gain. ### Transaction A financial operation processed through the Straddle platform, such as a `charge` or `payout`. ## W ### Watchlist screening The process of checking customer information against various sanctions and enforcement lists. ### Watchtower Straddle's transaction monitoring risk engine that provides built-in balance confirmation, real-time fraud detection, and risk assessment. ### Webhook A mechanism for receiving real-time notifications about events in the Straddle system. ### Withdrawal A type of funding event where money is pulled from an external bank account by Straddle, typically for payouts. # Business identity verification (KYB) Source: https://docs.straddle.com/guides/identity/business_identity Verify business entities with Straddle's KYB checks, including beneficial owner identification, EIN validation, and ongoing risk monitoring for ACH payments. Straddle provides an Identity Verification module specific for Business Customers, operating in similar ways to our Identity Verification module for Individuals. This guide walks you through the process of onboarding business customers using Straddle's API. ## Onboarding business customers using Straddle To onboard a business customer using Straddle's API, you'll need to follow these steps: 1. **Collect Business Information**: Gather the necessary information about the business, including: EIN, Legal Business Name, Business Address, and people associated with the business. 2. **Submit Business Information**: Use Straddle's API to submit the business information using the `POST /v1/customers` endpoint. 3. **Verify Business Identity**: Straddle's Identity Verification module processes the submitted information and generate a result for the business identity verification. The process is similar to the individual identity verification process, but with additional fields for business-specific information. Business identity verification will only be triggered if the `Compliance Profile` (`EIN` and `Legal Business Name`) and `Address` are provided. It will be skipped if not, and the customer will be moved directly to `verified` status. ## Business Identity reason codes When using Straddle's API for business verification, our system performs comprehensive checks on the business information you provide. These checks generate Business Identity (B) codes that offer insights into the verification results and help you make informed decisions about your business customers. ## Overview Business Identity codes are alphanumeric identifiers that start with the prefix "BI" and provide specific information about the business verification process. These codes help you understand: * Whether the submitted business information matches official records * The validity of the provided tax ID * Potential discrepancies in business names or addresses Business verification is crucial for regulatory compliance and fraud prevention. Always review these codes carefully to understand verification outcomes. ## Interpreting Business Identity codes Business Identity codes typically fall into several categories, each providing information about different aspects of the business verification process: ### Business name & tax ID verification These codes indicate whether the provided business name and tax ID match official records: | Code | Description | | - | - | | **BI102** | The provided tax ID is associated with the submitted business | | **BR103** | The provided tax ID does not appear to be associated with the submitted business | | **BI301** | The submitted business name aligns with official records | | **BI302** | Minor typographical discrepancies have been detected in the submitted business name | | **BR104** | The provided tax ID is linked to the individual named in the submission | | **BR105** | No confirmation is available that the provided tax ID belongs to the submitted business | | **BR304** | Notable discrepancies are present in the submitted business name compared to official records | | **BR305** | The submitted name appears to represent an individual rather than a business entity | ### Address verification These codes help verify the submitted business addresses: | Code | Description | | - | - | | **BI107** | The provided address is associated with the submitted business | | **BI108** | The provided address is situated near the address on record | | **BI109** | The provided address includes slight errors but closely matches the address on record | | **BR111** | The submitted address does not appear to be associated with the business | | **BR112** | Verification of the submitted address could not be established | ### People affiliation These codes provide information about the relationship between the submitted individuals and the business: | Code | Description | | - | - | | **BI601** | All named individuals appear to be affiliated with the submitted business | | **BI602** | At least one of the named individuals is affiliated with the submitted business | | **BI603** | Certain individuals not listed may also be affiliated with the submitted business | | **BR604** | None of the named individuals appear to be affiliated with the submitted business | | **BR605** | Affiliation of the named individuals with the submitted business could not be confirmed | ### OFAC / sanctions These codes indicate whether the business or associated individuals appear on sanctions lists: | Code | Description | | - | - | | **BI201** | No sanctions or OFAC listings are identified for the submitted business | | **BI202** | No sanctions or OFAC listings are identified for the named individuals | | **BR203** | Sanctions or OFAC listings appear to be associated with the submitted business | | **BR204** | Sanctions or OFAC listings appear to be associated with one or more of the named individuals | | **BR205** | Sanctions or OFAC listings appear to be associated with certain individuals found in existing records | | **BR705** | The provided business information is limited, incomplete, or of uncertain reliability | ### Registration & standing These codes provide information about the business's registration status: | Code | Description | | - | - | | **BV101** | The business maintains state-level registrations in multiple jurisdictions | | **BV102** | The business maintains registration solely in one jurisdiction | | **BV103** | The business is registered in a state frequently chosen for entity formation | | **BV104** | No active state registrations are identified for the business | | **BV501** | Registration records indicate an active status and good standing in all relevant states | | **BV502** | Registration records indicate active status and good standing in certain states, while others vary | | **BV503** | Registration records indicate an inactive status or poor standing in all identified states | ### Address characteristics These codes provide additional information about the nature of the business addresses: | Code | Description | | - | - | | **BI749** | At least one of the addresses provided is identified as commercial | | **BI754** | At least one of the addresses provided appears to be a post office box | | **BI755** | At least one of the addresses provided appears to be a virtual address | | **BR748** | At least one of the addresses provided is identified as residential | | **BR750** | At least one of the addresses provided appears to be that of a registered agent | | **BR751** | At least one of the addresses provided appears to be a Commercial Mail Receiving Agency (CMRA) | | **BR752** | At least one of the addresses provided appears to be a private mailbox | | **BR753** | At least one of the addresses provided is not currently accepting mail deliveries | ### Location usage These codes indicate how many other businesses are using the same address: | Code | Description | | - | - | | **BI801** | At least one submitted location is shared by 1–20 other businesses | | **BI802** | At least one submitted location is shared by 21–100 other businesses | | **BI803** | At least one submitted location is shared by more than 100 other businesses | ### Entity type These codes identify the legal structure of the business: | Code | Description | | - | - | | **BI010** | Records indicate the business is structured as a corporation | | **BI011** | Records indicate the business is structured as a limited liability company (LLC) | | **BI012** | Records indicate the business is registered as a nonprofit entity | | **BI013** | Records indicate the business operates as a partnership | | **BI014** | Records indicate the business is administered as a trust | ### Business formation & history These codes provide information about the business's establishment and history: | Code | Description | | - | - | | **BI500** | Formation records indicate an establishment date older than two years | | **BI501** | Formation records indicate the business was established within the past two years | | **BI503** | Formation records indicate the business was established within the past year | | **BI1101** | No record of any bankruptcy filings exists for the business | | **BR502** | Formation records indicate the business was established within the last month | | **BR1102** | Records indicate that the business has filed for bankruptcy | | **BR1201** | The provided TIN for the business is flagged or subject to a denylist status | If you encounter any Business Identity codes not listed in this documentation, contact Straddle support for clarification. Our verification system is continuously evolving to provide more detailed insights and better fraud protection. ## Using Business Identity codes in your application When implementing business verification in your application, you can use these codes to: 1. Automate decision-making based on verification outcomes 2. Implement custom workflows for businesses that require additional review 3. Provide specific feedback to users about their verification status 4. Track verification metrics to identify common issues or trends ## Best practices for business verification To maximize the effectiveness of your business verification process: 1. **Implement a tiered verification approach**: Use Business Identity codes to create different levels of verification based on risk and business type. 2. **Collect comprehensive business information**: The more detailed and accurate the initial business information, the more reliable the verification results will be. 3. **Consider industry-specific risks**: Some industries may require additional verification steps due to higher risk profiles. 4. **Provide clear feedback to users**: When a business fails verification, provide specific guidance on what information needs to be corrected. 5. **Monitor verification patterns**: Track common rejection reasons to identify potential improvements in your onboarding process. 6. **Implement periodic re-verification**: Business information can change over time, so consider implementing periodic re-verification for long-term customers. For businesses that require manual review, consider requesting additional documentation such as business licenses, articles of incorporation, or utility bills to verify the business address. ## Business Identity scores Straddle's Business Identity scores are calculated based on the Business Identity codes and provide a numerical representation of the business's verification status. These scores are not directly related to the business's creditworthiness or financial health. The Risk Scores range from 0 to 1 in the API, and are based on the number of codes in each category. The higher the risk score, the more scrutiny the business should receive in the event of a `review` status being assigned to it. ## Testing Business Identity in sandbox In Straddle's Sandbox environment, you can test Business Identity verification by providing specific data in the `address` object, a `business` customer type, and data in the `compliance_profile`. Each input maps to a specific outcome. | Address | Status | | - | - | | 1234 Sandbox Street, PO Box I304, Mock City, CA 94105 | `review` | | 1234 Sandbox Street, PO Box I301, Mock City, CA 94105 | `verified` | | 1234 Sandbox Street, PO Box I103, Mock City, CA 94105 | `rejected` | Any data that is not in the above list will return a random result while in Sandbox, but always return the same output for the same input. # Verifying customers and KYC Source: https://docs.straddle.com/guides/identity/customers Manage customers who send or receive payments through Straddle, including KYC identity verification, risk decisions, and reasons for review. Customers are the foundation of every payment flow in Straddle, representing the individuals or businesses who send and receive money through your platform. When you create a customer, Straddle automatically triggers identity verification, fraud screening, and compliance checks in real-time, enabling instant onboarding while maintaining security. ## What this guide covers This comprehensive guide provides everything you need to implement customer management: * **Customer lifecycle**: From creation through verification to ongoing monitoring * **Identity verification**: How automated KYC/AML checks work behind the scenes * **Review process**: Understanding and decisioning customers flagged for review * **Business customers**: Special requirements for company verification * **Best practices**: Optimizing approval rates while preventing fraud ## The customer object Every customer in Straddle represents either an `individual` person or a `business` entity. The customer object contains identity information, verification status, and metadata that enables secure payment processing. ### Core fields | Field | Type | Description | | - | - | :- | | `id` | string | Unique identifier for the customer, generated by Straddle | | `name` | string | Full name of the individual or business name | | `type` | string | Type of customer: `individual` or `business` | | `email` | string | Customer's email address | | `phone` | string | Customer's phone number in E.164 format (+1234567890) | | `external_id` | string | Your system's unique identifier for this customer | | `status` | string | Current verification status: `pending`, `review`, `verified`, `rejected`, `inactive` | ### Address object | Field | Type | Description | | - | - | :- | | `address.address1` | string | Primary address line | | `address.address2` | string | Secondary address line (optional) | | `address.city` | string | City name | | `address.state` | string | State code (2-letter abbreviation) | | `address.zip` | string | ZIP code (5 or 9 digits) | ### Compliance profile | Field | Type | Description | Applies To | | - | - | :- | :- | | `compliance_profile.dob` | string | Date of birth (YYYY-MM-DD format) | Individual | | `compliance_profile.ssn` | string | Full or last 4 digits of SSN (always masked in responses) | Individual | | `compliance_profile.ein` | string | Employer Identification Number | Business | | `compliance_profile.legal_business_name` | string | Legal entity name as registered | Business | | `compliance_profile.website` | string | Company's official website URL | Business | | `compliance_profile.representatives` | array | List of authorized representatives with ownership details | Business | ### Additional fields | Field | Type | Description | | - | - | :- | | `device.ip_address` | string | IP address (IPv4 or IPv6) captured during customer creation (used for fraud detection) | | `config` | object | Configuration options including sandbox testing outcomes | | `metadata` | object | Custom key-value pairs for your reference | | `created_at` | datetime | ISO 8601 timestamp of creation | | `updated_at` | datetime | ISO 8601 timestamp of last update | ## Automatic identity verification When you create a customer, Straddle automatically triggers a comprehensive verification pipeline that includes:
  • Fraud: Straddle employs a machine learning model trained with hundreds of predictors to detect the likelihood of identity fraud. Provides 98% instant risk decisions without the need for selfies.
  • Synthetic Identities: Purpose-built and trained with consortium data to tackle fake and randomized synthetic identity patterns. Produces highly accurate, real-time, actionable risk scores and reason codes, with 90% auto-capture in the riskiest 3% of users.
  • Email / Phone / Address Risk: Provides a risk score and correlation value for email addresses, phone numbers, and physical addresses. Risk scores use ML models trained on specific variables and layered with 800 million rows of known good and bad outcomes to predict the likelihood of fraud.
  • Device Risk (Coming Soon): Predicts risk associated with a device using data attributes such as IP, geolocation, device type, and device software. Device is the first application fraud solution that "binds" a device to the individual using it to counter application fraud and validate customer logins.

Know Your Customer (KYC) matches consumer-provided PII against the closest single identity on record or best-matched entity and returns a true or false value indicating the likelihood of a match. KYC is a legal requirement for financial institutions and financial services companies to establish a consumer's identity and identify risk factors.

Straddle KYC is accurately auditable and fully compliant with Section 326 of the US Patriot Act, the Customer Identification Program (CIP), and FinCEN's expanded Customer Due Diligence (CDD) program.

Include `dob` and `ssn` in the “Compliance Profile” of an API request when creating a customer to trigger KYC validation.

Global Watchlist Screening with Monitoring identifies risk by matching person and non-person entities against sanctions and enforcement lists, as well as Politically Exposed Persons (PEP) and adverse media registries worldwide.

Features

  • Sanctions and Enforcements Screening: Screen consumers and businesses during onboarding to identify if they are sanctioned or flagged by enforcement authorities.
  • PEP Screening: Screen individuals against PEP lists to identify those who could pose a higher Anti-Money Laundering (AML) risk.
  • Adverse Media Screening: Protect your company's reputation by identifying individuals associated with news items related to financial crimes.
  • Real-Time Monitoring: Continuously monitor existing customers in real time to determine if they appear on updated sanctions or PEP lists.
## Customer status lifecycle Every customer progresses through a defined verification lifecycle: | Status | Description | Next Actions | | - | - | - | | `pending` | Initial state, verification in progress | Wait for automatic verification to complete | | `review` | Manual review required (rare edge cases) | Use `/review` endpoint to see details, then `/decision` to approve/reject | | `verified` | Passed all verification checks | Ready to process payments | | `rejected` | Failed verification requirements | Cannot process payments, may need new customer | | `inactive` | Deactivated customer account | No longer able to transact | **Security**: SSN values are always masked in API responses. Use the `/unmasked` endpoint only when absolutely necessary and ensure proper access controls. ## Creating a customer To create a customer, you'll use the `POST /v1/customers` endpoint. Here's an example of how to create a customer using the Straddle API: ```bash theme={null} curl -X POST https://api.straddle.com/v1/customers \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "John Doe", "type": "individual", "email": "john.doe@example.com", "phone": "+1234567890", "address": { "address1": "123 Main St", "city": "Anytown", "state": "CA", "zip": "12345", "type": "residential" }, "compliance_profile": { "dob": "1990-01-01", "ssn": "123-45-6789" }, "external_id": "cust_123", "metadata": { "user_id": "user_123" } }' ``` ```javascript theme={null} const createCustomer = async () => { try { const res = await fetch('https://api.straddle.com/v1/customers', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: "John Doe", type: "individual", email: "john.doe@example.com", phone: "+1234567890", address: { address1: "123 Main St", city: "Anytown", state: "CA", zip: "12345", type: "residential" }, compliance_profile: { dob: "1990-01-01", ssn: "123-45-6789" }, external_id: "cust_123", metadata: { user_id: "user_123" } }) }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; createCustomer(); ``` This request creates a new customer with the provided information. The response includes a unique `id` for the customer, which you'll use for future operations. Ensure that you handle sensitive information like SSNs securely and in compliance with relevant regulations. ## Retrieving customer information To retrieve information about a customer, use the `GET /v1/customers/{id}` endpoint: ```bash theme={null} curl https://api.straddle.com/v1/customers/{id} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript theme={null} const getCustomer = async (id) => { try { const res = await fetch(`https://api.straddle.com/v1/customers/${id}`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; getCustomer('cust_123'); ``` ## Updating customer information You can update a customer's information using the `PUT /v1/customers/{id}` endpoint: ```bash theme={null} curl -X PUT https://api.straddle.com/v1/customers/{id} \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "John Smith", "email": "john.smith@example.com" }' ``` ```javascript theme={null} const updateCustomer = async (id) => { try { const res = await fetch(`https://api.straddle.com/v1/customers/${id}`, { method: 'PUT', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: "John Smith", email: "john.smith@example.com" }) }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; updateCustomer('cust_123'); ``` Updating certain fields may trigger a re-verification process, which could change the customer's status. ## Listing customers To retrieve a list of customers, use the `GET /v1/customers` endpoint. This endpoint supports pagination and various filter options: ```bash theme={null} curl "https://api.straddle.com/v1/customers?page_number=1&page_size=10&sort_by=created_at&sort_order=desc" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript theme={null} const listCustomers = async () => { try { const res = await fetch('https://api.straddle.com/v1/customers?page_number=1&page_size=10&sort_by=created_at&sort_order=desc', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; listCustomers(); ``` You can filter customers by various parameters such as `status`, `type`, `created_from`, `created_to`, and more. Refer to the API reference for a complete list of available filters. ## Handling review status When customers require manual review (status = `review`), use two endpoints to handle the review process: ### 1. Get review details Retrieve detailed verification results using `GET /v1/customers/{id}/review`: ```bash theme={null} curl https://api.straddle.com/v1/customers/{id}/review \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript theme={null} const getCustomerReview = async (id) => { try { const res = await fetch(`https://api.straddle.com/v1/customers/${id}/review`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; getCustomerReview('cust_123'); ``` The review response includes: * `identity_details`: Complete identity verification results including KYC, watchlist, reputation scores * `customer_details`: Current customer information * `messages`: Specific issues or requirements * `network_alerts`: Any consortium fraud signals ### 2. Make a decision After reviewing the details, make a decision using `PATCH /v1/customers/{id}/review`: ```bash theme={null} curl -X PATCH https://api.straddle.com/v1/customers/{id}/review \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "status": "verified" // or "rejected" }' ``` ```javascript theme={null} const updateCustomerReview = async (id) => { try { const res = await fetch(`https://api.straddle.com/v1/customers/${id}/review`, { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'verified' }) // or 'rejected' }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; updateCustomerReview('cust_123'); ``` ## Accessing sensitive data **Compliance Alert**: Access to unmasked data requires special permissions and generates audit logs. Only use when absolutely necessary for regulatory compliance or customer support. ### Retrieve unmasked data Use `GET /v1/customers/{id}/unmasked` to access full sensitive information: ```bash theme={null} curl https://api.straddle.com/v1/customers/{id}/unmasked \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript theme={null} const getUnmaskedCustomer = async (id) => { try { const res = await fetch(`https://api.straddle.com/v1/customers/${id}/unmasked`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } }; getUnmaskedCustomer('cust_123'); ``` The unmasked endpoint returns: * Full SSN (not just last 4 digits) * Complete compliance profile data * All sensitive fields in plaintext ## Best practices * Include full address (address1, city, state, zip) * Provide accurate phone numbers in E.164 format * Use legal names matching government IDs * Include SSN for immediate KYC verification * Use `/review` endpoint to understand issues * Make timely decisions with `/review` PATCH * Document decision rationale for compliance * Monitor review rates to identify patterns * Never log or store unmasked SSN data * Use `/unmasked` endpoint sparingly * Implement audit logging for sensitive access * Rotate API keys regularly * Set up customer status change notifications * React to review status immediately * Track verification success rates * Monitor for unusual patterns ## Understanding verification results The `/review` endpoint provides detailed verification results including: * **KYC Results**: Identity match confidence and specific field matches * **Reputation Scores**: Email, phone, and address risk assessments * **Watchlist Results**: Any sanctions, PEP, or adverse media hits * **Network Alerts**: Consortium fraud signals and patterns * **Messages**: Specific verification issues with reason codes For complete reason code reference, see [Reason Codes Guide](/guides/identity/reasons). ## Testing in sandbox Use the `config.sandbox_outcome` field to test different verification scenarios: ```json theme={null} { "name": "Test User", "type": "individual", "config": { "sandbox_outcome": "verified" // or "review", "rejected" } // ... other fields } ``` ## Business customers Business customers require additional fields in the compliance profile: * `ein`: Employer Identification Number * `legal_business_name`: Official registered name * `website`: Company website * `representatives`: Array of authorized signers with ownership percentages See [Business Identity Guide](/guides/identity/business_identity) for complete requirements. ## Next steps Complete endpoint documentation for customers Special requirements for business verification Understanding verification messages and codes Set up real-time customer status notifications # Risk models and scoring Source: https://docs.straddle.com/guides/identity/models Understand Straddle's identity and fraud risk assessment system, including decision logic, risk scores, correlation scores, and how scores affect approvals. Straddle's identity verification engine uses machine learning models trained on millions of data points to assess risk in real-time. When you create a customer, multiple scoring models analyze different aspects of the provided information—from synthetic identity patterns to email reputation—delivering a comprehensive risk assessment within milliseconds. ## What this guide covers * **Decision outcomes**: How Straddle determines customer status (verified, review, rejected) * **Risk scores**: Understanding fraud and synthetic identity scoring ranges * **Correlation scores**: How PII elements are validated against each other * **Breakdown structure**: Accessing detailed scores for each verification module * **Implementation patterns**: Using scores to optimize approval rates ## Understanding the review response When you call `GET /v1/customers/{id}/review`, the response contains detailed scoring breakdowns organized by verification module: ```json theme={null} { "identity_details": { "breakdown": { "fraud": { "decision": "accept", "risk_score": 0.125, "codes": ["I520", "I601"] }, "synthetic": { "decision": "accept", "risk_score": 0.089, "codes": ["I1004"] }, "email": { "decision": "accept", "correlation_score": 0.75, "correlation": "match", "codes": ["I556"] }, "phone": { "decision": "accept", "correlation_score": 0.82, "correlation": "match", "codes": ["I618"] }, "address": { "decision": "accept", "correlation_score": 0.91, "correlation": "match", "codes": ["I708"] } } } } ``` ### Breakdown modules Each module evaluates a specific aspect of identity: | Module | Purpose | Key Metrics | | - | - | - | | `fraud` | Overall fraud risk assessment | `risk_score` | | `synthetic` | Synthetic identity detection | `risk_score` | | `email` | Email reputation and correlation | `correlation_score`, `correlation` | | `phone` | Phone verification and correlation | `correlation_score`, `correlation` | | `address` | Address validation and correlation | `correlation_score`, `correlation` | | `business_identification` | Business-specific verification (business customers only) | Various | ### Decision values Each module returns a `decision` field with one of these values: | Decision | Meaning | Impact on Customer Status | | - | - | - | | `accept` | Module passed verification | Contributes to `verified` status | | `review` | Manual review recommended | May trigger `review` status | | `reject` | Module failed verification | May trigger `rejected` status | The overall customer status is determined by combining all module decisions. A single `reject` or multiple `review` decisions typically result in a non-verified status. ## Risk scores Risk scores predict the likelihood of fraud, with higher scores indicating greater risk: ### Score interpretation Risk scores range from 0 to 1, with higher scores indicating greater risk. Your platform should define thresholds based on your risk tolerance. ### Fraud risk score The `fraud.risk_score` evaluates overall identity fraud probability based on: * Consistency of provided PII * Velocity patterns (multiple applications) * Known fraud indicators * Behavioral anomalies ### Synthetic identity risk score The `synthetic.risk_score` specifically detects fabricated identities: * Randomized SSN patterns * Inconsistent credit history * Unusual PII combinations * Missing digital footprint ### Accessing risk scores ```javascript theme={null} // Get detailed review information const review = await straddle.customers.review(customerId); // Access risk scores from breakdown const fraudScore = review.identity_details.breakdown.fraud.risk_score; const syntheticScore = review.identity_details.breakdown.synthetic.risk_score; if (fraudScore > 0.7 || syntheticScore > 0.9) { // High risk - implement additional verification console.log('Customer requires enhanced due diligence'); } ``` ## Correlation scores Correlation scores measure how well PII elements match authoritative data sources: ### Correlation categories The `correlation` field categorizes the strength of correlation: | Category | Meaning | | - | - | | `high_confidence` | Strong correlation - PII elements verified together | | `likely_match` | Good correlation - most elements match | | `potential_match` | Partial correlation - some elements match | | `low_confidence` | Weak or no correlation - elements don't match records | ### Module-specific correlations * **Email Correlation**: Verifies email ownership and age * **Phone Correlation**: Confirms phone number association * **Address Correlation**: Validates current residence ### Using correlation scores ```javascript theme={null} const review = await straddle.customers.review(customerId); const { email, phone, address } = review.identity_details.breakdown; // Check correlation strength if (email.correlation === 'low_confidence') { console.log('Email cannot be verified - request alternative email'); } if (phone.correlation_score < 0.5) { console.log('Weak phone correlation - verify phone ownership'); } // All correlations strong if (email.correlation === 'high_confidence' && phone.correlation === 'high_confidence' && address.correlation === 'high_confidence') { console.log('All PII elements strongly correlated'); } ``` ## KYC validation The `kyc` object in the review response provides field-level validation: ```json theme={null} { "identity_details": { "kyc": { "decision": "accept", "codes": ["I998"], "validations": { "first_name": true, "last_name": true, "address": true, "city": true, "state": true, "zip": true, "phone": true, "email": true, "dob": true, "ssn": false // SSN doesn't match records } } } } ``` ### Field validation results * `true`: Field matches authoritative data sources * `false`: Field doesn't match or cannot be verified * Field may be omitted if not provided ### Using KYC results ```javascript theme={null} const review = await straddle.customers.review(customerId); const kyc = review.identity_details.kyc; // Check overall KYC decision if (kyc.decision !== 'accept') { console.log('KYC verification failed'); } // Count failed validations const failedFields = Object.entries(kyc.validations) .filter(([field, valid]) => valid === false) .map(([field]) => field); if (failedFields.length > 0) { console.log(`Failed KYC fields: ${failedFields.join(', ')}`); // Request correction of specific fields } ``` ## Implementation best practices * Design a workflow to handle customers needing review * Identify common review scenarios for your organization * Provide operations users with guidance on how to handle specific cases * Track average risk scores over time * Identify common reason codes * Analyze correlation patterns * Optimize data collection * Implement fallbacks for `unknown` correlations * Collect additional data when needed * Provide clear user feedback * Document decision rationale * Use sandbox to test score ranges * Simulate different risk scenarios * Verify decision logic * Monitor false positive rates ## Next steps Understand the specific codes returned with scores API reference for accessing detailed scores Learn about sanctions and PEP screening Special scoring for business customers # Identity verification overview Source: https://docs.straddle.com/guides/identity/overview An overview of Straddle's identity verification platform, including KYC and KYB checks, fraud scoring, watchlists, and reputation data for ACH payments. Straddle Identity is a graph-defined identity engine that instantly verifies customers while detecting fraud patterns across hundreds of predictors. Built directly into the customer creation flow, Identity eliminates the complexity of managing separate KYC, AML, and fraud prevention systems—delivering 98% instant risk decisions without requiring selfies or manual reviews. ## Why identity matters for payments Traditional payment systems treat identity verification as a compliance checkbox. Straddle takes a different approach: by solving identity first, we enable: * **Instant onboarding**: Sub-second verification decisions for 98% of legitimate users * **Fraud prevention**: Detect synthetic identities, account takeovers, and first-party fraud before they impact your platform * **Regulatory compliance**: Automated KYC/AML screening that exceeds Patriot Act and FinCEN requirements * **Network intelligence**: Leverage consortium data to identify risks invisible to single-provider solutions ## How Straddle Identity works Every customer creation automatically triggers our comprehensive identity verification pipeline: 1. **Real-time verification** against authoritative data sources 2. **Risk scoring** using ML models trained on millions of outcomes 3. **Watchlist screening** against global sanctions and PEP databases 4. **Continuous monitoring** for changes in risk profile post-onboarding All of this happens seamlessly through a single API call to create a customer. ## Features
  • Fraud: Straddle employs a machine learning model trained with hundreds of predictors to detect the likelihood of identity fraud. Provides 98% instant risk decisions without the need for selfies.
  • Synthetic Identities: Purpose-built and trained with consortium data to tackle fake and randomized synthetic identity patterns. Produces highly accurate, real-time, actionable risk scores and reason codes, with 90% auto-capture in the riskiest 3% of users.
  • Email / Phone / Address Risk: Provides a risk score and correlation value for email addresses, phone numbers, and physical addresses. Risk scores use ML models trained on specific variables and layered with 800 million rows of known good and bad outcomes to predict the likelihood of fraud.
  • Device Risk (Coming Soon): Predicts risk associated with a device using data attributes such as IP, geolocation, device type, and device software. Device is the first application fraud solution that "binds" a device to the individual using it to counter application fraud and validate customer logins.

Know Your Customer (KYC) matches consumer-provided PII against the closest single identity on record or best-matched entity and returns a true or false value indicating the likelihood of a match. KYC is a legal requirement for financial institutions and financial services companies to establish a consumer's identity and identify risk factors.

Straddle KYC is accurately auditable and fully compliant with Section 326 of the US Patriot Act, the Customer Identification Program (CIP), and FinCEN's expanded Customer Due Diligence (CDD) program.

Global Watchlist Screening with Monitoring identifies risk by matching person and non-person entities against sanctions and enforcement lists, as well as Politically Exposed Persons (PEP) and adverse media registries worldwide.

Features

  • Sanctions and Enforcements Screening: Screen consumers and businesses during onboarding to identify if they are sanctioned or flagged by enforcement authorities.
  • PEP Screening: Screen individuals against PEP lists to identify those who could pose a higher Anti-Money Laundering (AML) risk.
  • Adverse Media Screening: Protect your company's reputation by identifying individuals associated with news items related to financial crimes.
  • Real-Time Monitoring: Continuously monitor existing customers in real time to determine if they appear on updated sanctions or PEP lists.
Synthetic identity fraud occurs when genuine information is merged with fabricated information to create a new synthetic identity. Businesses in the US are projected to lose \$5.8B in 2024 to synthetic identity fraud. ## People make payments The first step to process a Straddle payment is to create a **customer** to represent an end-user and their information. You can use **Identity** as the first step in a payment journey or as a standalone verification service. A **customer** resource can represent either a person or a business. The customer resource helps manage payments, linked wallets, transaction history, identity verification, and payouts between your application and your users. ### Creating a customer To create a customer and initiate identity verification, use the [Create a Customer](/api-reference/customers/create) API endpoint: ```bash theme={null} POST /v1/customers ``` ```json theme={null} { "name": "Jane Doe", "email": "jane.doe@example.com", "type": "individual", "address": { "line1": "123 Main St", "city": "Anytown", "state": "NY", "postal_code": "12345", "country": "US" }, "compliance_profile": { "date_of_birth": "1980-01-01", "social_security_number": "123-45-6789" }, "external_id": "your_system_identifier" } ``` ### Reviewing identity verification results After creating a customer, you can review the identity validation results to assess risk and compliance. Use the [Review a Customer's Identity Validation Results](/api-reference/customers/review) endpoint: ```bash theme={null} GET /v1/customers/{id}/review ``` This endpoint provides: Assess the likelihood of fraud. Understand specific factors affecting the decision. Identify any matches with global watchlists. Detect any consortium alerts on the identity. ### Integration with the core data model Identity verification is seamlessly integrated into the core customer data model. When you create or update a customer, identity verification processes are automatically triggered, ensuring real-time risk assessment and compliance checks. By incorporating identity verification into the customer lifecycle, Straddle enables you to: Detect fraudulent identities before processing payments. Meet KYC and AML regulatory requirements effortlessly. Provide a smooth experience for legitimate users while mitigating risk. For detailed information on customer management and identity verification, refer to the [Customers API Reference](/api-reference/customers/create). # Identity verification reason codes Source: https://docs.straddle.com/guides/identity/reasons Reference for the reason codes returned by Straddle's identity verification process, including what each code means and how to handle reviews and rejections. Reason codes are the detailed signals that explain exactly why a customer passed or failed identity verification. Each code represents a specific finding—from "email address is over 2 years old" (I553) to "multiple identities associated with SSN" (R203). Codes give you granular insight into verification decisions and enable intelligent retry logic. ## Understanding code categories Reason codes follow a consistent naming pattern that indicates their type and severity: | Prefix | Category | Meaning | Action Required | | - | - | - | - | | `I` | Informational | Positive or neutral signals | None - supports verification | | `R` | Risk Indicator | Potential fraud or discrepancy | Review or additional verification | | `BI` | Business Info | Business-specific positive signals | None - supports business verification | | `BR` | Business Risk | Business-specific risk indicators | Review business documentation | Focus on `R` codes first. These indicate the specific issues preventing verification. Use `I` codes to understand what IS working correctly. ## Where codes appear Reason codes are returned in the `codes` array within each breakdown module: ```javascript theme={null} const review = await straddle.customers.review(customerId); // Each module has its own codes array const fraudCodes = review.identity_details.breakdown.fraud.codes; const emailCodes = review.identity_details.breakdown.email.codes; const phoneCodes = review.identity_details.breakdown.phone.codes; // Example response console.log(fraudCodes); // ["I1004", "I520", "R203"] // ↑ ↑ ↑ // Match 4+ Consortium | Email low risk | Multiple SSNs ``` ## Critical risk codes These codes typically result in immediate rejection or review: ### Identity fraud indicators | Code | Description | Suggested Action | | - | - | - | | `R201` | Invalid SSN format | Verify SSN and re-submit | | `R203` | Multiple identities with SSN | High fraud risk - manual review | | `R298` | Manipulated synthetic identity | Reject - synthetic fraud pattern | | `R299` | Fabricated synthetic identity | Reject - synthetic fraud pattern | ### Verification failures | Code | Description | Suggested Action | | - | - | - | | `R551` | Invalid email address | Request valid email | | `R603` | Invalid phone number | Update phone number | | `R703` | Address doesn't exist | Verify address format | | `R901` | SSN cannot be resolved | Additional documentation needed | ### Watchlist hits | Code | Description | Suggested Action | | - | - | - | | `R180` | OFAC SDN list match | Compliance review required | | `R184` | Politically exposed person | Enhanced due diligence | | `R185` | Adverse media | Investigation required | ## Implementation patterns ### Automated response logic ```javascript theme={null} async function handleReasonCodes(customerId) { const review = await straddle.customers.review(customerId); const allCodes = []; // Collect all codes from all modules Object.values(review.identity_details.breakdown).forEach(module => { if (module.codes) allCodes.push(...module.codes); }); // Priority 1: Check for blocking codes const blockingCodes = ['R180', 'R184', 'R298', 'R299']; if (allCodes.some(code => blockingCodes.includes(code))) { return { action: 'reject', reason: 'High risk or compliance issue' }; } // Priority 2: Check for fixable issues const fixableIssues = { 'R201': 'Invalid SSN - please verify', 'R551': 'Invalid email - please update', 'R603': 'Invalid phone - please update', 'R703': 'Address not found - please verify' }; for (const [code, message] of Object.entries(fixableIssues)) { if (allCodes.includes(code)) { return { action: 'request_update', message, field: getFieldFromCode(code) }; } } // Priority 3: Check risk threshold const riskCodes = allCodes.filter(code => code.startsWith('R')); if (riskCodes.length > 5) { return { action: 'manual_review', codes: riskCodes }; } // All clear return { action: 'approve' }; } ``` ### User-friendly error messages ```javascript theme={null} const CODE_MESSAGES = { // Invalid input 'R201': 'The Social Security Number appears to be invalid. Please double-check and re-enter.', 'R551': 'We couldn\'t verify this email address. Please use your primary email.', 'R603': 'This phone number couldn\'t be verified. Please ensure it\'s a valid US number.', 'R703': 'We couldn\'t find this address. Please verify the street address and ZIP code.', // Identity issues 'R203': 'We need additional information to verify your identity. Please contact support.', 'R298': 'We\'re unable to verify your identity at this time. Please contact support.', // Watchlist 'R180': 'Additional review required. Our compliance team will contact you within 24 hours.', }; function getUserMessage(codes) { for (const code of codes) { if (CODE_MESSAGES[code]) { return CODE_MESSAGES[code]; } } return 'We need to review your application. You\'ll hear from us soon.'; } ``` ## Best practices * Handle blocking codes first (watchlist, synthetic) * Then fixable issues (invalid input) * Finally risk assessment (velocity, correlation) * Always provide actionable feedback * Monitor most frequent codes * Identify false positive patterns * Optimize data collection based on failures * Adjust risk thresholds over time * Prepare for new codes * Group related codes for handling * Cache code lookups for performance * Log all codes for analysis * Translate codes to clear messages * Specify exactly what needs fixing * Avoid exposing raw codes to users * Provide support paths for complex issues ## Common code patterns ### Successful verification Typically includes these informational codes: * `I1004` or `I1005`: Found in consortium data * `I520`, `I620`, `I720`: Low risk scores * `I556`, `I618`, `I708`: PII elements resolved ### Needs manual review Often includes these combinations: * `I1001` + multiple `R` codes: New identity with risks * `R1001-R1009`: Velocity or inconsistency issues * `R160-R166`: Suspect but not confirmed fraud ### Auto-reject patterns * `R298` or `R299`: Synthetic identity * `R180-R185`: Watchlist matches * Multiple `R140-R146`: Negative tags ## Reason codes documentation | Code | Description | | - | - | | **I1001** | Identity not found within Consortium Institutions | | **I1002** | National ID was not provided and Straddle was unable to prefill National ID for the given identity | | **I1003** | National ID was not provided and Straddle was able to prefill National ID for the given identity | | **I1004** | Matched identity onto at least 1 other Consortium Institution | | **I1005** | Matched identity onto at least 4 other Consortium Institutions | | **I121** | Social networks match | | **I127** | Online sources represent a broader digital footprint than just social networks | | Code | Description | | - | - | | **I140** | Email address tagged as positive | | **I141** | Email domain tagged as positive | | **I142** | Phone number tagged as positive | | **I143** | IP Address tagged as positive | | **I144** | Full name tagged as positive | | **I145** | SSN tagged as positive | | **I146** | Device tagged as positive | | Code | Description | | - | - | | **I202** | The input SSN is an ITIN | | **I203** | SSN was first seen in credit header records between 5 to 10 years ago | | **I204** | SSN is first seen in credit header records more than 10 years ago | | **I205** | SSN is found to be inquired once every 2 to 3 months | | **I206** | SSN is found to be inquired once every 3 to 6 months | | **I207** | SSN is found to be inquired once every 6 to 12 months | | **I208** | SSN is found to be inquired less than once a year | | **I209** | Input full name and DOB combination found in property records | | **I210** | Input full name and DOB combination found in education/university records | | **I211** | Input full name and DOB matches a driver's license record | *** ### Account verification codes | Code | Description | | - | - | | **I301** | Account is correlated with the first name | | **I302** | Account is conditionally correlated with the first name | | **I304** | Account is correlated with the last name | | **I305** | Account is conditionally correlated with the last name | | **I307** | Account is correlated with the business name | | **I308** | Account is conditionally correlated with the business name | | **I310** | Account is correlated with the DOB | | **I311** | Account is conditionally correlated with the DOB | | **I313** | Account is correlated with the SSN | | **I314** | Account is conditionally correlated with the SSN | | **I316** | Account is correlated with the address | | **I317** | Account is conditionally correlated with the address | | **I319** | Account is correlated with the phone | | **I320** | Account is conditionally correlated with the phone | | Code | Description | | - | - | | **I325** | SSN derived from ID Graph | | **I326** | DOB derived from ID Graph | | **I328** | Account has been seen in the last 15 days | | **I329** | Account has been seen between 15 and 30 days | | **I330** | Account has been seen between 30 and 45 days | | **I331** | Account has been seen between 45 and 60 days | | **I332** | Account has been seen between 60 and 75 days | | **I333** | Account has been seen between 75 and 90 days | | **I334** | Account has been seen between 90 and 120 days | | **I335** | Account has been seen between 120 and 150 days | | **I336** | Account has been seen between 150 and 180 days | | **I337** | Account has been seen between 180 and 210 days | | **I338** | Account has been seen between 210 and 240 days | | **I339** | Account has been seen between 240 and 270 days | | **I341** | Account has been seen between 270 and 300 days | | **I342** | Account has been seen between 300 and 365 days | | **I343** | Account has been seen between 365 and 730 days | | **I344** | Account has been seen over 730 days ago | *** ### Device verification codes | Code | Description | | - | - | | **I401** | Device token previously encountered | | **I402** | Multiple users associated with device | | **I403** | Identity may not be primary device user | | **I404** | Identity associated with primary device owner | | **I405** | Device token previously associated with phone number | | **I406** | Device token previously associated with email address | | **I407** | Device token previously associated with first name | | **I408** | Device token previously associated with last name | | **I409** | Device token not encountered within the past 5 days | | **I410** | Device session is associated with more than 2 phone numbers | | **I411** | Device session is associated with more than 2 emails | | **I412** | Device session is associated with more than 2 first names | | **I413** | Device session is associated with more than 2 last names | | **I414** | Session connected using a proxy | | **I415** | Session IP located more than 100 miles from the address | | **I416** | Session IP originates from within the United States | | **I417** | Session IP originates from outside the United States | | **I419** | Session connected using a residential IP address | | **I420** | Session connected using a commercial IP address | | **I421** | Session connected using a mobile IP address | | **I423** | Device is a physical device | | **I424** | Device type is a desktop or laptop computer | | **I425** | Device type is mobile, tablet, or wearable | | **I428** | Mobile network associated with the device is a non-US carrier | *** ### Email verification codes | Code | Description | | - | - | | **I520** | Email risk score represents low risk | | **I550** | Email address is more than 180 days and less than 1 year old | | **I551** | Email address is more than 1 year and less than 2 years old | | **I553** | Email address is more than 2 years old | | **I554** | Exact match between email and first name | | **I555** | Email domain is more than 180 days old | | **I556** | Email address can be resolved to the individual | | **I557** | Email is correlated with the first name | | **I558** | Email is correlated with the last name | | **I559** | Exact match between email and last name | | **I560** | Email domain represents a Fortune 500 company | | **I561** | Email domain represents a US college or university | | **I562** | Email username contains ZIP code of current application | | **I563** | Email domain contains a special use domain (RFC, arpa, example, invalid, local, onion, etc.) | | **I564** | Special characters found in email alias | | **I565** | Email username contains a role-level alias (support, info, admin, etc.) | | **I566** | Email provider is found in public web sources | | **I567** | Email username contains five or more alphabetic sections | | **I568** | Email handle contains a name | | **I569** | Email handle contains input first name | | **I570** | Email handle contains input surname | | **I571** | Email top-level domain represents a non-US country | | **I572** | Email subdomain possibly a typo of a popular email domain | | **I573** | Email top-level domain possibly a typo of a popular TLD | | **I575** | Provided email is a possible filler email | | **I576** | Email handle aligns with the pattern of valid email addresses | *** ### Phone verification codes | Code | Description | | - | - | | **I601** | Phone number is a landline | | **I602** | Phone number is a mobile line | | **I605** | Phone number is a premium-rate line | | **I608** | Phone number is commercial or dual-purpose | | **I609** | Phone number is consumer or residential | | **I610** | Phone number is correlated with the address | | **I611** | Phone number is associated with a major US carrier | | **I614** | Phone number has been in service more than 365 days | | **I616** | Phone number is associated with a Mobile Virtual Network Operator | | **I618** | Phone number can be resolved to the individual | | **I620** | Phone risk score represents low risk | | **I621** | Phone is correlated with the first name | | **I622** | Phone is correlated with the last name | | **I623** | Exact match between phone and first name | | **I624** | Exact match between phone and last name | | **I625** | Phone number has never been ported | | **I626** | Phone number was ported at least 60 days ago | | **I630** | Phone subscriber has been correlated with the input phone number for more than 365 days | | Code | Description | | - | - | | **I631** | IP address is provided by a mobile carrier | | **I632** | IP connection is consumer | | **I633** | IP connection is business | | **I634** | Proxy is an educational institution | | **I635** | Proxy is registered to a corporation | | **I636** | IP address originates from the US or US territories | | **I637** | Email address is associated with the input phone number | | **I638** | IP proxy originates from Google or Apple consumer privacy networks | | **I639** | IP address is a consumer privacy network proxy | | **I640** | Phone number might have been mistyped | | **I641** | Presented identity shows high overall correlation in Straddle's network | *** ### Address verification codes | Code | Description | | - | - | | **I704** | Address is multi-unit or high-rise | | **I705** | Address is single unit | | **I706** | Address is an accredited college or university | | **I707** | Address is residential | | **I708** | Address can be resolved to the individual | | **I709** | Address is correlated with the first name | | **I710** | Address is correlated with the last name | | **I711** | Address is confirmed as deliverable | | **I712** | Address is confirmed deliverable by dropping secondary information | | **I713** | Address is confirmed deliverable but was missing secondary information | | **I714** | Address is valid but doesn't currently receive USPS street delivery | | **I715** | Address is correlated with a past address | | **I716** | Address is a Small Office/Home Office (SOHO) | | **I718** | Exact match between address and first name | | **I719** | Exact match between address and last name | | **I720** | Address risk score represents low risk | | **I721** | Email address is correlated with the input physical address | | **I722** | Email address is partially correlated with the input physical address | *** ### General information codes | Code | Description | | - | - | | **I903** | Address was not provided at input | | **I904** | SSN/ITIN was not provided at input | | **I905** | SSN/ITIN provided at input contained only 4 digits | | **I906** | DOB was not provided at input | | **I907** | SSN is issued to a non-US citizen | | **I908** | Address is correlated with a military ZIP code | | **I909** | First name and last name are possibly reversed | | **I910** | Address is correlated with a past address | | **I911** | Address is a PO Box | | **I912** | SSN was randomly issued by the SSA | | **I913** | SSN has not been reported as deceased | | **I914** | Identity has not been reported as deceased | | **I917** | Full name and address can be resolved to the individual but the SSN/ITIN is not | | **I919** | Full name, address, and SSN/ITIN can be resolved to the individual | | **I920** | Emerging identity indicator | | **I921** | Address is an accredited college or university | | **I922** | Mobile number was not provided at input | | **I923** | Email address was not provided at input | | **I930** | Name and DOB match a notable personality or celebrity | | **I931** | First name or last name may refer to a non-person entity | | **I932** | Name and DOB match a notable individual in the sports industry | | **I933** | Multi-party application detected | | **I975** | Non-MLA covered borrower status | | **I998** | Name, SSN, and DOB correlation verified by SSA | | **I999** | Identity decease unverified by SSA | *** ### Risk codes | Code | Description | | - | - | | **R1001** | Found at least 2 distinct DOBs associated with the given identity | | **R1002** | Found at least 4 distinct first names associated with the given identity | | **R1003** | Found at least 4 distinct last names associated with the given identity | | **R1004** | Found at least 3 distinct phone numbers associated with the given identity | | **R1005** | Found at least 3 distinct emails associated with the given identity | | **R1006** | Found at least 1 application marked as fraudulent associated with the given identity | | **R1007** | Found at least 1 application marked as third-party fraud associated with the given identity | | **R1008** | Found at least 2 applications within 30 days of each other associated with the given identity | | **R1009** | Found at least 2 applications within 90 days of each other associated with the given identity | | Code | Description | | - | - | | **R1010** | Found at least 1 account marked as fraudulent associated with the given identity | | **R1011** | Found at least 1 account marked as suspected third-party fraud associated with the given identity | | **R1012** | Found at least 1 account marked as suspected first-party fraud associated with the given identity | | **R1013** | Found at least 1 account marked as other fraud associated with the given identity | | **R1014** | Found at least 1 account marked as delinquency associated with the given identity | | **R1015** | Found at least 1 closed account associated with the given identity | | **R1016** | Found at least 5 closed accounts associated with the given identity | | **R1017** | Found at least 2 accounts opened within 30 days of each other associated with the given identity | | **R1018** | Found at least 2 accounts opened within 90 days of each other associated with the given identity | | **R1019** | Found at least 2 accounts closed within 30 days of each other associated with the given identity | | **R1020** | Found at least 2 accounts reported as fraud within 30 days of each other associated with the given identity | | **R1021** | Found at least 1 account closed within 30 days from opening associated with the given identity | | **R1022** | Found at least 1 account reported as fraud within 30 days from opening associated with the given identity | | Code | Description | | - | - | | **R1023** | Found at least 1 ACH transaction reported as fraud associated with the given identity | | **R1024** | Found at least 1 ACH transaction reported as suspected third-party fraud associated with the given identity | | **R1025** | Found at least 1 ACH transaction reported as suspected first-party fraud associated with the given identity | | **R1026** | Found at least 1 ACH transaction reported as other fraud associated with the given identity | | **R1027** | Found at least 1 ACH transaction reported as delinquency associated with the given identity | | **R1028** | Found at least 10 returned ACH transactions associated with the given identity | | **R1029** | Found at least 1 returned ACH transaction with return category fraudulent behavior associated with the given identity | | **R1030** | Found at least 1 ACH transaction reported as fraud within 7 days of another associated with the given identity | | **R1031** | Found at least 1 ACH transaction reported as fraud committed within 7 days from account opening associated with the given identity | | **R1032** | Found at least 1 ACH transaction reported as fraud committed within 30 days from account opening associated with the given identity | | Code | Description | | - | - | | **R110** | Alert list email address match | | **R111** | Alert list SSN/ITIN match | | **R113** | Alert list phone number match | | Code | Description | | - | - | | **R140** | Email address tagged as negative | | **R141** | Email domain tagged as negative | | **R142** | Phone number tagged as negative | | **R143** | IP Address tagged as negative | | **R144** | Full name tagged as negative | | **R145** | SSN tagged as negative | | **R146** | Device tagged as negative | | **R160** | Email address tagged as suspect | | **R161** | Email domain tagged as suspect | | **R162** | Phone number tagged as suspect | | **R163** | IP Address tagged as suspect | | **R164** | Full name tagged as suspect | | **R165** | SSN tagged as suspect | | **R166** | Device tagged as suspect | | Code | Description | | - | - | | **R171** | Input mobile number originates from an OFAC sanctioned country | | **R172** | Input email likely originates from an OFAC sanctioned country | | **R173** | Input country or document is from an OFAC sanctioned country | | **R180** | Watchlist search returned at least one hit on OFAC SDN list | | **R181** | Watchlist search returned at least one hit on OFAC Non-SDN lists | | **R182** | Watchlist search returned at least one hit on a sanction list excluding any OFAC hits | | **R183** | Watchlist search returned at least one hit on an enforcement list excluding any OFAC hits | | **R184** | Watchlist search returned at least one hit on a politically exposed person | | **R185** | Watchlist search returned at least one entity with adverse media articles | | **R186** | Global Watchlist sources selected are correlated with the input identifiers | | **R189** | Watchlist search returned at least one entity on any custom watchlist that matched the input | | Code | Description | | - | - | | **R201** | The input SSN is invalid | | **R202** | The input SSN is reported as deceased | | **R203** | Multiple identities associated with input SSN | | **R204** | Entered SSN associated with multiple last names | | **R205** | Entered SSN associated with different name and address | | **R206** | The input SSN was issued prior to the input date-of-birth | | **R207** | SSN/ITIN is associated with multiple DOBs | | **R208** | SSN/ITIN is associated with multiple addresses | | **R209** | No former addresses associated with the SSN | | **R210** | Frequency of SSN in Straddle records is unusually high | | **R211** | SSN seen in frozen credit files | | **R212** | The input last name is not associated with the input SSN | | **R213** | Name does not correlate with the name for the resolved public record individual | | **R214** | SSN/ITIN cannot be resolved to the individual | | **R215** | First name does not match SSN | | **R216** | Unable to verify date-of-birth | | **R217** | SSN was randomly issued by the SSA | | **R218** | The input SSN is not the primary SSN for the input identity | | **R219** | The input SSN is not found in public records | | **R220** | Issue date for the provided SSN could not be resolved | | **R221** | SSN associated with input phone number could not be confirmed | | **R222** | Input SSN could not be confirmed | | **R223** | Input SSN did not match any of the SSNs associated with the input phone number in the last two years | | **R224** | 4 or more different SSNs have been found to be inquired against the input phone | | **R225** | 4 or more different first names have been found to be inquired against the input SSN | | **R226** | Multiple phones are marked current for the input SSN | | **R227** | SSN is found to be inquired at an unusually high frequency (more than once a month) | | **R228** | Only 1 component of the input DOB matches the best matched entity | | **R229** | Only 2 components of the input DOB matches the best matched entity | | **R230** | SSN was first seen in credit header records within the last 1 year | | **R231** | SSN was first seen in credit header records between 1 to 3 years ago | | **R232** | SSN was first seen in credit header records between 3 to 5 years ago | | **R233** | No SSN found in credit header records for the given full name and DOB | | **R234** | SSNs in credit header data associated with full name and DOB differ from input SSN by 1 digit | | **R235** | Input full name could not be fuzzy-matched with full names associated with SSN in header and inquiry records | | **R236** | Input DOB month does not match any DOB month found on inquiry records | | **R237** | Input SSN is not an exact match to the SSNs associated with the given full name and DOB | | **R238** | SSNs in credit header data associated with full name and DOB differ from input SSN by up to 2 digits | | **R239** | SSNs in credit header data associated with full name and DOB differ from input SSN by up to 3 digits | | **R240** | Input SSN was issued more than 2 years after input birth year | | Code | Description | | - | - | | **R298** | Identity resembles a manipulated synthetic identity | | **R299** | Identity resembles a fabricated synthetic identity | | Code | Description | | - | - | | **R350** | DOB indicates individual is less than 16 or more than 100 years old | | **R351** | DOB indicates COPPA review | | **R352** | DOB indicates an age between 13 and 15 | | **R353** | DOB indicates an age between 16 and 17 | | **R355** | DOB indicates an improbable age | # Consumer reputation and friendly fraud Source: https://docs.straddle.com/guides/identity/reputation Identify and stop friendly fraud, chargebacks, and ACH returns with consumer reputation and identity data powered by Straddle's consortium network. ## Overview Straddle Reputation matches provided consumer PII (Personally Identifiable Information) and account information against data collected from diverse institutions across the US, including: * Fintechs and neobanks * Traditional banks * Lenders * Gaming platforms * Telcos and more The service returns crucial risk signals that can associate a consumer identity with past instances of confirmed fraudulent or high-risk activities. Additionally, Straddle Reputation includes a dedicated risk score focused on identifying repeat bad actors. ## About reputation risk signals Straddle Reputation risk signals are indicators or warnings derived from our extensive consortium data. These signals suggest whether a consumer identity has been involved in past fraudulent or deceitful behavior, particularly concerning first-party fraud. You can use these risk signals to help predict the likelihood that a consumer might make bad faith disputes or default on payments. This assessment is based on confirmed, fraudulent activities and can be utilized at various stages: * During the account opening process * At the point of a transaction * When handling a disputed transaction ## Use cases Identify consumers who are likely to commit payment fraud based on their past activity for transactions such as ACH, card, check, and loan applications Identify and flag applicants previously linked to fraud schemes or transaction disputes. These individuals can then be routed for manual review or subjected to enhanced scrutiny. Detect signals in consumer behavior that are indicative of patterns of fraudulent chargebacks or payment disputes. ## API integration Integrating Straddle Reputation into your systems is straightforward -- it's built in to the existing customer creation flow! The API response provides an additional object with a comprehensive overview of the risk assessment. ### API response example Below is an example of the reputation object returned by the Straddle API: ```json theme={null} { "reputation": { "decision": "accept", "codes": [ "I1004", "R1015", "R1023", "R1027" ], "risk_score": 123, "insights": { "ach_fraud_transactions_count": 123, "ach_fraud_transactions_total_amount": 123, "ach_fraud_transactions_dates": [ "2023-12-25" ], "ach_returned_transactions_count": 123, "ach_returned_transactions_total_amount": 123, "ach_returned_transactions_dates": [ "2023-12-25" ], "card_fraud_transactions_count": 123, "card_fraud_transactions_total_amount": 123, "card_fraud_transactions_dates": [ "2023-12-25" ], "card_disputed_transactions_count": 123, "card_disputed_transactions_total_amount": 123, "card_disputed_transactions_dates": [ "2023-12-25" ], "card_stopped_transactions_count": 123, "card_stopped_transactions_dates": [ "2023-12-25" ], "accounts_count": 123, "accounts_active_count": 123, "accounts_closed_count": 123, "accounts_closed_dates": [ "2023-12-25" ], "accounts_fraud_count": 123, "accounts_fraud_loss_total_amount": 123, "accounts_fraud_labeled_dates": [ "2023-12-25" ], "applications_count": 123, "applications_dates": [ "2023-12-25" ], "applications_approved_count": 123, "applications_declined_count": 123, "applications_fraud_count": 123, "user_institution_count": 123, "user_dob_count": 123, "user_mobile_count": 123, "user_email_count": 123, "user_address_count": 123, "user_active_profile_count": 123, "user_closed_profile_count": 123 } } } ``` ### Key fields in the response A recommended action (e.g., "accept", "review", "reject") based on the risk assessment. An array of Reputation Codes that provide specific reasons and context for the assessment. A numerical score indicating the level of risk associated with the identity, particularly for identifying repeat bad actors. A detailed object containing various data points and metrics used in the risk assessment. ## Understanding insights The insights object within the API response provides a granular breakdown of the data points contributing to the risk assessment. Straddle provides insights into an identity's past behavior, including confirmed fraud and payment defaults. Number of fraudulent ACH transactions associated with the identity Total amount of fraudulent ACH transactions Dates of fraudulent ACH transactions Number of returned ACH transactions Total amount of returned ACH transactions Number of fraudulent card transactions Total amount of fraudulent card transactions Number of disputed card transactions Total amount of disputed card transactions Number of stopped card transactions Total number of accounts associated with the identity Number of active accounts Number of closed accounts Dates when accounts were closed Number of accounts marked as fraudulent Total loss amount from fraudulent accounts Total number of applications Dates of applications Number of approved applications Number of declined applications Number of applications marked as fraudulent Number of institutions where the user has been seen Number of different DOBs associated with the identity Number of mobile numbers associated with the identity Number of email addresses associated with the identity Number of addresses associated with the identity Number of active profiles Number of closed profiles These insights allow for a deeper understanding of the factors influencing the risk score and decision, enabling more informed risk management strategies. Always ensure you have proper consent and legal basis for processing this data in accordance with applicable privacy laws. ## Reputation codes The following codes provide detailed information about the findings related to the consumer identity. Use these codes to understand specific risk signals identified by the system. | Code | Description | | :- | :- | | I1001 | Identity not found within Consortium Institutions | | I1002 | National ID was not provided and Straddle was unable to prefill National ID for the given identity | | I1003 | National ID was not provided and Straddle was able to prefill National ID for the given identity | | I1004 | Matched identity onto at least 1 other Consortium Institution | | I1005 | Matched identity onto at least 4 other Consortium Institutions | | R1001 | Found at least 2 distinct DOBs associated with the given identity | | R1002 | Found at least 4 distinct first names associated with the given identity | | R1003 | Found at least 4 distinct last names associated with the given identity | | R1004 | Found at least 3 distinct phone numbers associated with the given identity | | R1005 | Found at least 3 distinct emails associated with the given identity | | R1006 | Found at least 1 application marked as fraudulent associated with the given identity | | R1007 | Found at least 1 application marked as third party fraud associated with the given identity | | R1008 | Found at least 2 applications within 30 days of each other associated with the given identity | | R1009 | Found at least 2 applications within 90 days of each other associated with the given identity | | R1010 | Found at least 1 account marked as fraudulent associated with the given identity | | R1011 | Found at least 1 account marked as suspected Third-Party Fraud associated with the given identity | | R1012 | Found at least 1 account marked as suspected First-Party Fraud associated with the given identity | | R1013 | Found at least 1 account marked as Other Fraud associated with the given identity | | R1014 | Found at least 1 account marked as Delinquency associated with the given identity | | R1015 | Found at least 1 closed account associated with the given identity | | R1016 | Found at least 5 closed accounts associated with the given identity | | R1017 | Found at least 2 accounts that were opened within 30 days from each other associated with the given identity | | R1018 | Found at least 2 accounts that were opened within 90 days from each other associated with the given identity | | R1019 | Found at least 2 accounts that were closed within 30 days from each other associated with the given identity | | R1020 | Found at least 2 accounts that were reported as Fraud within 30 days from each other associated with the given identity | | R1021 | Found at least 1 account that has been closed within 30 days from opening associated with the given identity | | R1022 | Found at least 1 account that has been reported as Fraud within 30 days from opening associated with the given identity | | R1023 | Found at least 1 ACH transaction reported as Fraud associated with the given identity | | R1024 | Found at least 1 ACH transaction reported as Suspected Third-Party Fraud associated with the given identity | | R1025 | Found at least 1 ACH transaction reported as Suspected First-Party Fraud associated with the given identity | | R1026 | Found at least 1 ACH transaction reported as Other Fraud associated with the given identity | | R1027 | Found at least 1 ACH transaction reported as Delinquency associated with the given identity | | R1028 | Found at least 10 returned ACH transactions associated with the given identity | | R1029 | Found at least 1 returned ACH transaction with return category Fraudulent Behavior associated with the given identity | | R1030 | Found at least 1 ACH transaction reported as Fraud within 7 days from one another associated with the given identity | | R1031 | Found at least 1 ACH transaction reported as Fraud which was committed within 7 days from account opening associated with the given identity | | R1032 | Found at least 1 ACH transaction reported as Fraud which was committed within 30 days from account opening associated with the given identity | | R1033 | Found at least 1 Check transaction reported as Fraud associated with the given identity | | R1034 | Found at least 1 Check transaction reported as Suspected Third-Party Fraud associated with the given identity | | R1035 | Found at least 1 Check transaction reported as Suspected First-Party Fraud associated with the given identity | | R1036 | Found at least 1 Check transaction reported as Other Fraud associated with the given identity | | R1037 | Found at least 1 Check transaction reported as Delinquency associated with the given identity | | R1038 | Found at least 1 returned Check transaction with a return category Fraudulent Behavior associated with the given identity | | R1039 | Found at least 2 check transactions reported as Fraud within 7 days from one another associated with the given identity | | R1040 | Found at least 2 check transactions reported as Fraud within 30 days from one another associated with the given identity | | R1041 | Found at least 1 Check transaction reported as Fraud which was committed within 7 days from account opening associated with the given identity | | R1042 | Found at least 1 Check transaction reported as Fraud which was committed within 30 days from account opening associated with the given identity | | R1043 | Found at least 10 disputed Card transactions associated with the given identity | | R1044 | Found at least 20 disputed Card transactions associated with the given identity | | R1045 | Found at least 5 Unauthorized disputed Card transactions associated with the given identity | | R1046 | Found at least 5 Authorized disputed Card transactions associated with the given identity | | R1047 | Found at least 5 Granted disputed Card transactions associated with the given identity | | R1048 | Found at least 10 Granted disputed Card transactions associated with the given identity | | R1049 | Found at least 2 disputed Card transactions within 1 day from one another associated with the given identity | | R1050 | Found at least 2 disputed Card transactions within 7 days from one another associated with the given identity | | R1051 | Found at least 1 disputed Card transaction committed within 1 day from account opening associated with the given identity | | R1052 | Found at least 1 disputed Card transaction committed within 7 days from account opening associated with the given identity | | R1053 | Found at least 7 distinct emails associated with the given fullname and date of birth combination | | R1054 | Found at least 7 distinct phones associated with the given identity | | R1055 | Matched identity onto at least 17 other transaction consortium institutions | | R1056 | Matched Fullname and date of birth combination onto at least 16 other transaction consortium institutions | | R1057 | Matched Fullname, date of birth and SSN combination onto at least 10 other transaction consortium institutions | | R1058 | Found at least 4 distinct emails associated with the given identity | | R1059 | Found at least 3 to 6 distinct emails associated with the given fullname and date of birth combination | | R1060 | Seen input phone number in at least 13 other transaction consortium institutions | | R1061 | Seen input phone number with in at least 4 distinct emails in transaction consortium | | R1062 | Found at least 1 fraud event reported for the input identity | # Sanctions watchlist screening Source: https://docs.straddle.com/guides/identity/watchlists Screen customers against OFAC, sanctions, and global watchlists during identity verification to prevent money laundering and stay AML compliant. Straddle screens all customers against a comprehensive set of sanctions and enforcement lists. These lists ensure that no transactions are made with individuals or entities that are flagged by international governing bodies. Straddle provides access to over **10,000 lists** globally. If your business requires broader coverage or additional screening for Politically Exposed Persons (PEPs) or Adverse Media, contact your account manager to discuss extended screening options. ## Core sanctions and enforcement lists Here are some of the primary lists included in Straddle's screening: | Source Name | Country | | - | - | | EU External Action Service - Consolidated list of Sanctions | EU | | OFAC SDN List | US | | OFAC Consolidated List | US | | United Nations Consolidated | UN | | United Kingdom HM Treasury Office of Financial Sanctions Implementation Consolidated List | GB | | Consolidated Canadian Autonomous Sanctions List | CA | | United States Department of State Nonproliferation Sanctions List | US | | United States Department of State Terrorist Exclusion List | US | | Source Name | Country | | - | - | | United States Financial Crimes Enforcement Network 311 Special Measures | US | | United States Bureau of Industry and Security Entity List | US | | United States System for Award Management Exclusions (excl. OFAC) | US | | Fitness Probity United States Medicaid Exclusions Lists OIG LEIE | US | | United States Department of Justice Executive Office for Immigration Review Disciplined Practitioners | US | | United States Bureau of Industry and Security The Denied Persons List | US | | United States Treasury FinCEN Enforcement Actions | US | | United States OCC Enforcements | US | | United States Drug Enforcement Agency Fugitives | US | | United States Immigration and Customs Wanted | US | | United States Marshals Most Wanted | US | | FBI Most Wanted | US | | United States Federal Reserve Prohibition from Banking | US | For broader coverage, including Politically Exposed Persons (PEPs) and Adverse Media, contact your Straddle account manager. # Welcome to Straddle Source: https://docs.straddle.com/guides/overview Get started with Straddle's APIs for ACH and bank payments, identity verification, and embedded platforms. Find guides, references, and integration tools. Straddle is a unified platform for building modern account-to-account payment experiences. \ \ Onboard and verify customers, connect to their accounts, and get paid faster. Trade in your messy payments stack for Straddle, where everything is built to work together. ## Core functionality Onboard and verify individual or business customers in less than a second with Straddle Identity, a graph-defined identity engine built-in to your Straddle account. Connect customer identity to open banking data via Bridge, Straddle's "no-code" widget, or use existing tokens from providers like Mastercard (Finicity), Plaid, and MX. All payments are protected with built-in balance confirmation and real-time fraud detection through Watchtower, Straddle's transaction monitoring risk engine. 24-hour direct debit funding, with payouts via dynamic multi-rail orchestration across ACH, RTP, and FedNow (coming soon). Integrated KYC, watchlist screening, and transaction monitoring ensure robust compliance without engineering overhead. A single, secure API stack that simplifies complex infrastructure into easy-to-implement code. ## How does it work? Here's a high-level overview of how Straddle works: Use Straddle's API to create a [customer](/guides/identity/customers) profile. Straddle automatically scores multi-dimensional risk and compliance signals. [Bridge](/guides/bridge/overview) connects your application to the banking network. You can connect through Straddle's drop-in [widget](/guides/bridge/widget) or use existing tokens from supported providers like [Plaid](/guides/bridge/plaid-token), MX, and Finicity. Once a bank account is connected, a [paykey](/guides/bridge/paykeys) is created and returned to your application. A paykey is a secure token linking the verified identity to the bank account. This is actually pretty cool technology: [learn more](/guides/resources/waldo). Use the paykey to initiate charges or payouts through Straddle's API, benefiting from built-in balance verification and fraud prevention. Returning customers skip right to this step! ## Core products Straddle offers several core products that are designed to work together: Straddle [Identity](/guides/identity/overview) is the foundation of our platform, providing robust customer management and identity verification features: * Instant onboarding and verification of individual or business customers * Uses Straddle ID, a graph-defined identity engine * Integrated KYC and AML compliance checks * Manages customer profiles, including contact information and payment preferences * Real-time fraud detection through Watchtower, our transaction monitoring risk engine Straddle [Bridge](/guides/bridge/overview) is our account connectivity suite that securely links users to their financial accounts: * Offers a drop-in open banking [widget](/guides/bridge/widget) connecting to 90% of US bank accounts * Supports existing third-party tokens from providers like [Plaid](/guides/bridge/plaid-token), MX, and Mastercard (Finicity) * Provides API-based [bank account](/guides/bridge/bank-account) verification for "out of network" banks * Generates [Paykeys](/guides/bridge/paykeys), secure tokens linking verified identities to payment methods * Enables balance checks and account information retrieval Bridge also supports manual entry of routing and account numbers. This feature is particularly useful for existing customers or in situations where an open-banking connection isn't possible. It ensures that you can create Paykeys and process payments even when direct bank connectivity isn't available or preferred. Straddle [Pay by Bank](/guides/paybybank) is our unified payment processing solution: * Uses [Paykeys](/guides/bridge/paykeys) generated by [Bridge](/guides/bridge/overview) to initiate charges or payouts * Supports various payment rails including ACH, RTP, and FedNow (coming soon) * Provides built-in fraud detection and compliance checks for all transactions * Enables 24-hour direct debits with built-in balance and risk scoring * Offers a simple API for initiating and managing payments Straddle [Embed](/guides/embed/overview) is our solution for platforms, allowing them to offer Straddle's capabilities to their own users: * Purpose-built API stack for software providers, marketplaces, and payment facilitators * Allows platforms to extend and monetize Straddle's payments infrastructure * Provides white-label solutions for identity verification, account linking, and payment processing * Handles regulatory compliance, reducing liability for platforms * Offers flexible integration options to suit various platform architectures These core products work seamlessly together, enabling you to quickly implement sophisticated payment functionality, reduce fraud, and provide a seamless experience for your users. # Pay by Bank: account-to-account payments Source: https://docs.straddle.com/guides/paybybank Introduction to Straddle's unified Pay by Bank API for ACH and account-to-account payments, including verification, paykeys, and multi-rail processing. Pay by Bank is Straddle's core product, providing a unified API for account-to-account payments. It combines identity verification, open banking connectivity, and payment processing to offer developers a streamlined solution for implementing secure and efficient payment flows. ## Technical components Pay by Bank consists of three main components: Graph-based identity engine for real-time verification Open banking connectivity suite for account linking and paykey generation Send or receive payments directly from any bank account ## Key features for developers * **Unified API**: Single integration point for identity, open banking, and payments * **Real-time Identity Verification**: Sub-second customer onboarding, no selfies required * **Bank Account Connectivity**: Connect to 90%+ of US bank accounts with our Bridge SDK or bring your own token * **Fraud Prevention**: Built-in transaction monitoring * **Multi-rail Orchestration**: Optimize for speed across ACH, RTP, and FedNow (coming soon) * **Webhook Support**: Real-time notifications for asynchronous events **Bridge also supports bank routing and account numbers** \ \ This feature is particularly useful for existing customers or in situations where an open-banking connection isn't possible. ## Integration overview Implementing Pay by Bank involves interacting with three primary API endpoints: 1. **Customers API**: Manage customers with Straddle ID built-in 2. **Bridge API**: Handle bank account connections and paykey generation 3. **Payments API**: Initiate and manage payment transactions across multiple rails ## Implementation workflow Use the Customers API to create and verify customer identities. Implement the Bridge API to securely link customer bank accounts and generate Paykeys. Use the Payments API with generated paykeys to initiate and manage transactions. Set up webhook endpoints to receive real-time updates on transaction statuses and other events. For detailed information on request/response formats, parameters, and endpoint-specific functionality, refer to our comprehensive API reference: * [Customers API Reference](/api-reference/customers) * [Bridge API Reference](/api-reference/bridge) * [Payments API Reference](/api-reference/payments) We're just getting started with this guide. Keep reading to learn a *whole lot more*. Or skip to the end and start coding. # Charges: collect ACH bank payments Source: https://docs.straddle.com/guides/payments/charges Use Straddle charges to collect ACH payments from customer bank accounts, with built-in balance checks, fraud screening, and configurable processing rails. Charges are debit transactions that pull funds from a customer's bank account through the ACH network. This guide covers the complete charge lifecycle, from creation through settlement, including status management, balance verification, and handling returns. Charges are [ACH debit transactions](/help/ACH101/ach-debit) that require proper [customer authorization](/help/Payment-Compliance/ach-auth). Understanding [ACH basics](/help/ACH101/ach-basics) helps ensure compliant implementation and reduces return rates. ## What you'll learn This comprehensive guide walks you through: * Creating charges with required fields and optional configurations * Understanding the payment status lifecycle and when charges can be modified * Implementing balance verification to reduce NSF failures * Handling failures and returns with specific reason codes * Managing charges through hold, release, and cancellation operations * Testing charge scenarios in sandbox before production Whether you're implementing subscription billing, one-time purchases, invoice collection, or account funding, this guide provides the patterns and best practices for successful charge implementation. Charges require a `paykey`: a token representing a verified bank account. Learn about connecting bank accounts in the [Bridge guide](/guides/bridge/overview). ## The charge object A charge represents a debit transaction with comprehensive status tracking and metadata: ```json theme={null} { "id": "ch_def456abc", "paykey": "pk_abc123xyz", "amount": 10000, "currency": "USD", "description": "Monthly subscription - October 2024", "payment_date": "2024-10-01", "status": "paid", "status_details": { "message": "Payment successfully completed", "reason": "ok", "source": "system", "code": null, "changed_at": "2024-10-03T09:00:00Z" }, "external_id": "inv_12345", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "config": { "balance_check": "enabled" }, "metadata": { "order_id": "ord_789", "customer_ref": "cust_456" }, "payment_rail": "ACH", "paykey_details": { "bank_name": "Chase Bank", "last4": "6789", "account_type": "checking" }, "customer_details": { "name": "John Doe", "email": "john@example.com" }, "trace_number": "071000301234567", "funding_ids": ["fe_abc123"], "status_history": [...], "created_at": "2024-10-01T10:00:00Z", "updated_at": "2024-10-03T09:00:00Z" } ``` ### Core fields | Field | Type | Description | | - | - | - | | `id` | string | Unique charge identifier | | `paykey` | string | Token for customer's bank account | | `amount` | integer | Amount in cents (10000 = \$100.00) | | `currency` | string | Currency code (USD only) | | `description` | string | Statement descriptor | | `payment_date` | string | Processing date (YYYY-MM-DD) | | `status` | string | Current payment status | | `status_details` | object | Detailed status information | | `external_id` | string | Your unique reference | | `consent_type` | string | How consent was obtained | | `trace_number` | string | ACH network tracking number | | `funding_ids` | array | Related settlement events | ## Creating a charge View detailed schema and request information on the [Create a Charge API Reference](/api-reference/charges/create). ```bash cURL theme={null} curl -X POST https://sandbox.straddle.com/v1/charges \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paykey": "pk_abc123xyz", "amount": 10000, "currency": "USD", "description": "Monthly subscription - October 2024", "payment_date": "2024-10-01", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "inv_12345", "config": { "balance_check": "enabled" } }' ``` ```javascript Node.js theme={null} const charge = await straddle.charges.create({ paykey: "pk_abc123xyz", amount: 10000, currency: "USD", description: "Monthly subscription - October 2024", payment_date: "2024-10-01", consent_type: "internet", device: { ip_address: "192.168.1.1" }, external_id: "inv_12345", config: { balance_check: "enabled" } }); ``` ```python Python theme={null} charge = straddle.charges.create( paykey="pk_abc123xyz", amount=10000, currency="USD", description="Monthly subscription - October 2024", payment_date="2024-10-01", consent_type="internet", device={ "ip_address": "192.168.1.1" }, external_id="inv_12345", config={ "balance_check": "enabled" } ) ``` ```json 201 Created theme={null} { "meta": { "api_request_id": "3a2b1c4d-0e6f-4a88-9876-123456abcdef", "api_request_timestamp": "2024-10-01T10:00:00Z" }, "response_type": "object", "data": { "id": "ch_def456abc", "paykey": "pk_abc123xyz", "amount": 10000, "currency": "USD", "description": "Monthly subscription - October 2024", "payment_date": "2024-10-01", "status": "created", "status_details": { "message": "Payment successfully created and awaiting validation.", "reason": "ok", "source": "system", "changed_at": "2024-10-01T10:00:00Z" }, "external_id": "inv_12345", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "config": { "balance_check": "enabled" }, "metadata": {}, "created_at": "2024-10-01T10:00:00Z", "updated_at": "2024-10-01T10:00:00Z" } } ``` ```json 400 Bad Request theme={null} { "meta": { "api_request_id": "f1b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b" }, "response_type": "error", "error": { "status": 400, "type": "validation_error", "title": "Invalid Input Data", "detail": "The request contains invalid field values.", "items": [ { "reference": "paykey", "detail": "The provided paykey is invalid or expired." } ] } } ``` ## Required parameters Payment key for the customer's verified bank account. Obtained via Bridge flow. Amount to charge in cents. Must be positive. Example: `10000` for \$100.00 ISO 4217 currency code. Currently only `"USD"` is supported. Description appearing on bank statements. Maximum 80 characters. Be clear and recognizable. Date to process payment (YYYY-MM-DD). Can be today or future-dated up to 90 days. How customer consent was obtained: * `"internet"` - Online or mobile app authorization * `"signed"` - Signed agreement or contract * `"telephone"` - Phone authorization Learn more about [authorization requirements](/help/Payment-Compliance/ach-auth) and the difference between [internet vs. contract authorization](/help/Payment-Compliance/consent-types) for ACH compliance. Customer device information for fraud prevention. Customer's IP address at authorization time. Use `"0.0.0.0"` for offline consent. Your unique identifier for this charge. Must be unique across all charges. Used for idempotency. Processing configuration options. Balance verification mode: * `"enabled"` - Attempts check, proceeds if unavailable (recommended) * `"required"` - Must verify balance to proceed * `"disabled"` - No verification attempted For testing only. Simulates specific outcomes in sandbox environment. ## Optional parameters Custom key-value pairs. Maximum 20 keys, 40 characters per key/value. ## Payment status lifecycle Charges progress through these statuses: | Status | Description | Can Modify? | | - | - | - | | `created` | Initial state, awaiting verification | ✅ Yes | | `scheduled` | Verified and queued for processing | ✅ Yes | | `pending` | Sent to payment network | ❌ No | | `paid` | Successfully completed | ❌ No | | `failed` | Declined before funding | ❌ Terminal | | `reversed` | Returned after funding | ❌ Terminal | | `cancelled` | Stopped before network submission | ❌ Terminal | | `on_hold` | Paused for review | ⚠️ Depends | **Critical**: Once a charge reaches `pending` status, it has been submitted to the payment network and CANNOT be stopped, held, or cancelled. ### Status details Every status change includes detailed information: ```json theme={null} "status_details": { "message": "Payment failed due to insufficient funds", "reason": "insufficient_funds", "source": "bank_decline", "code": "R01", "changed_at": "2024-10-02T14:30:00Z" } ``` | Field | Description | | - | - | | `message` | Human-readable explanation | | `reason` | Machine-readable reason code | | `source` | Where the status change originated | | `code` | ACH return code (when applicable) | | `changed_at` | When the status changed | For complete status reasons and ACH codes, see [Payment Statuses Guide](/guides/payments/statuses). Learn about [ACH return codes](/help/nacha-rules/ach-return) and [NACHA compliance](/help/nacha-rules/ach-rules) for better error handling. ## Common operations ### [Retrieve a charge](/api-reference/charges/retrieve) ```bash theme={null} curl -X GET https://sandbox.straddle.com/v1/charges/{charge_id} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### [Update a charge](/api-reference/charges/update) Update charges in `created` or `scheduled` status: ```bash theme={null} curl -X PUT https://sandbox.straddle.com/v1/charges/{charge_id} \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 15000, "description": "Updated amount - Monthly subscription", ... }' ``` ### [Cancel a charge](/api-reference/charges/cancel) Cancel charges before they reach `pending` status: ```bash theme={null} curl -X POST https://sandbox.straddle.com/v1/charges/{charge_id}/cancel \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Customer requested cancellation" }' ``` ### [Place on hold](/api-reference/charges/hold) Pause a charge for review (only in `created` or `scheduled` status): ```bash theme={null} curl -X POST https://sandbox.straddle.com/v1/charges/{charge_id}/hold \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Awaiting inventory confirmation" }' ``` ### [Release a hold](/api-reference/charges/release) Release user-initiated holds only: ```bash theme={null} curl -X POST https://sandbox.straddle.com/v1/charges/{charge_id}/release \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Inventory confirmed" }' ``` System holds (`watchtower` source) cannot be released via API. They require manual review in the dashboard. ### Resubmit a charge [Re-attempt](/guides/payments/statuses#resubmit-failed-payments) a charge using the [resubmit](https://straddle.dev/api-reference#tag/charge/POST/v1/charges/\{id}/resubmit) endpoint. This creates a new transaction that inherits the original payment's details. ```shellscript theme={null} curl -X POST https://api.straddle.com/v1/charges/{id}/resubmit \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "payment_date": "2026-03-01", "description": "Customer requested retry after payday", "external_id": "my-custom-external-id" }' ``` ## Balance verification Balance checks help reduce NSF returns: | Mode | Behavior | Use Case | | - | - | - | | `enabled` | Attempts check, proceeds if unavailable | **Recommended** - Best balance | | `required` | Must verify balance to proceed | High-value transactions | | `disabled` | No verification attempted | Future-dated charges | Balance verification is part of Straddle's [account validation](/help/Payment-Compliance/account-validation) process that helps reduce NSF returns and improve payment success rates. **`required`** fails charges if: * The paykey was created with manual bank account entry * The bank doesn't provide balance information * Balance service is temporarily unavailable ## Handling failures When charges fail, check `status_details` for specific information: ```javascript theme={null} if (charge.status === 'failed') { switch(charge.status_details.reason) { case 'insufficient_funds': // Retry after notifying customer break; case 'closed_bank_account': // Request new payment method break; case 'disputed': // Do not retry - investigate break; case 'risk_review': // Compliance review needed break; } } ``` ## Testing in sandbox Use `sandbox_outcome` in the config to simulate scenarios: ```json theme={null} { "paykey": "pk_test123", "amount": 5000, "config": { "balance_check": "enabled", "sandbox_outcome": "paid" // or "failed_insufficient_funds", etc. } // ... other required fields } ``` Common test scenarios: * `"paid"` - Successful charge * `"failed_insufficient_funds"` - NSF failure * `"on_hold_daily_limit"` - Risk hold * `"reversed_customer_dispute"` - Post-funding reversal ## Webhooks Set up [webhooks](/webhooks/overview/101) to receive real-time charge updates. ## Best practices Always include a unique `external_id` to prevent duplicate charges Set up webhooks to track payment lifecycle in real-time Implement retry logic for transient failures like NSF Use sandbox to test all failure scenarios before production ## Next steps Complete charge endpoint documentation Detailed status flows and ACH codes Learn about sending money to customers Set up real-time notifications # Funding events and reconciliation Source: https://docs.straddle.com/guides/payments/funding Understand how Straddle ACH payments settle, how funding events are generated, and how to reconcile charges, payouts, and fees with your accounting system. Funding events represent the actual movement of money between Straddle and your linked bank accounts. They're the financial backbone that connects your payment operations to real bank transfers. While charges and payouts handle individual transactions, funding events track the net settlements that appear in your bank statements. ## Why funding events matter Understanding funding events is essential for: * **Financial reconciliation**: Match bank statement entries to specific payments * **Cash flow management**: Predict when funds will arrive or be withdrawn * **Accounting accuracy**: Track deposits, withdrawals, and reversals with funding event IDs and trace numbers * **Operational monitoring**: Identify settlement patterns and handle exceptions This guide explains how charges and payouts translate into funding events, settlement timing, and reconciliation workflows that keep your books balanced. ## What are funding events? Funding events track all money movement between Straddle and your external bank accounts. They are automatically generated when: * **Charges settle** - Deposits to your account from successful charges * **Payouts are initiated** - Withdrawals from your account to fund payouts * **Returns occur** - Reversals of previously settled charges * **Payouts fail** - Returns of failed payout attempts Funding events represent the **net settlement** to your bank account, not individual transactions. Multiple charges or payouts may be bundled into a single funding event. ## Funding event types Straddle uses four funding event types that describe both direction and reason: | Event Type | Direction | Description | When It Occurs | | - | - | - | - | | `charge_deposit` | Deposit (credit) | Successful charges being deposited | Daily settlement of paid charges | | `charge_reversal` | Withdrawal (debit) | Previously deposited charges being returned | When funded charges reverse (R01, R10, etc.) | | `payout_withdrawal` | Withdrawal (debit) | Funds being withdrawn for payouts | Before payouts are sent to recipients | | `payout_return` | Deposit (credit) | Failed payouts being returned | When payouts fail or are returned | ## Understanding transfer direction The `direction` field describes money movement from your linked bank account's perspective: | Direction | Meaning | Impact on Your Balance | | - | - | - | | `deposit` | Money coming INTO your account | Increases balance | | `withdrawal` | Money going OUT of your account | Decreases balance | ## Settlement timing Straddle's default funding time is **one business day** (`one_day`) based on the payment's effective date: A charge or payout is created with a `payment_date` The `effective_date` is when the payment enters the payment date Settlement occurs one business day after the effective date: * Monday effective → Tuesday funding * Friday effective → Monday funding (skips weekend) Your linked bank account receives the net settlement ### Example timeline **Monday Charge Example:** * Created Monday 8pm → Effective Tuesday → Funded Wednesday **Friday Charge Example:** * Created Friday 2pm → Effective Friday → Funded Monday (skips weekend) **Critical Distinction for Payouts vs Charges:** * **Charges**: Funding events occur AFTER the charge completes (`paid` status) * **Payouts**: Funding events occur BEFORE the payout is sent (withdrawal to fund the payout) This means payout funding events represent Straddle collecting funds from you to send to recipients. ## Funding event structure Each funding event contains: ```json theme={null} { "id": "fe_abc123def456", "amount": 150000, // $1,500.00 in cents "direction": "deposit", "event_type": "charge_deposit", "payment_count": 12, // Number of payments in this event "transfer_date": "2024-10-23", "trace_number": "071000301234567", "trace_numbers": [ "071000301234567", "071000301234568" ] } ``` ### Field descriptions | Field | Description | | - | - | | `id` | Unique identifier for the funding event. Primary key for bank reconciliation. | | `amount` | Total amount in cents | | `direction` | `deposit` or `withdrawal` | | `event_type` | Type of funding event | | `payment_count` | Number of individual payments bundled | | `transfer_date` | Date funds were transferred | | `trace_number` | Primary ACH trace number. Available on the funding event but not guaranteed to appear on bank statements. | | `trace_numbers` | All trace numbers if multiple | ## Reconciling to your bank statement Each funding event produces a single ACH transfer to or from your linked bank account. The ACH file includes an addenda record on that transfer containing: * The funding event `id` (e.g., `fe_abc123def456`) * A plain-text description matching the `event_type`: `charge deposit`, `payout withdrawal`, `charge reversal`, or `payout return` Your bank displays the addenda alongside the transfer entry, giving you a direct reference back to the Straddle funding event. Reconciliation is circular: the `id` in the bank statement addenda is the same `id` returned by the Straddle API. Use the funding event `id` as the primary key when matching bank statement entries to Straddle records. It appears reliably in the ACH addenda record and maps directly to the identifier returned by the API. **Trace numbers as a backup.** Trace numbers are available on every funding event (`trace_number`, `trace_numbers`), but they are not guaranteed to appear on bank statements. Some financial institutions strip or do not surface addenda fields in their transaction exports. Treat trace numbers as a secondary reference when the funding event `id` is unavailable. ## Charge funding flow Understanding how charges become funding events: 1. **Charge Created** (Monday 8pm) 2. **Scheduled** for processing 3. **Pending** - Sent to network (Tuesday morning) 4. **Funding Event Created** (Tuesday) - Type: `charge_deposit` 5. **Paid** - Successfully completed (Wednesday morning) 6. Money deposited to your account If a charge is later returned: 7. **Reversed** status on charge 8. **Reversal Funding Event** created (next day) - Type: `charge_reversal` 9. Money withdrawn from your account ### Example: Multiple charges, single funding event Monday's charges: * Charge 1: \$100.00 - Paid Tuesday * Charge 2: \$250.00 - Paid Tuesday * Charge 3: \$75.00 - Paid Tuesday Wednesday's funding event: ```json theme={null} { "id": "fe_wednesday123", "amount": 42500, // $425.00 total "direction": "deposit", "event_type": "charge_deposit", "payment_count": 3, "transfer_date": "2024-10-23" } ``` ## Payout funding flow Payouts require funding BEFORE being sent: 1. **Payout Created** - Needs funding 2. **Funding Event Created** - Type: `payout_withdrawal` 3. **Money Withdrawn** from your account 4. **Payout Sent** to recipient 5. **Payout Paid** - Successfully completed If payout fails: 6. **Payout Failed** status 7. **Return Funding Event** created - Type: `payout_return` 8. **Money Deposited Back** to your account ### Example: Payout funding sequence 1. **Monday**: Create \$500 payout 2. **Monday**: Funding event withdraws \$500 from your account 3. **Tuesday**: Payout sent to recipient 4. **Wednesday**: Payout completes successfully If payout fails: 5. **Thursday**: Payout marked as `failed` 6. **Friday**: Return funding event deposits \$500 back ## Searching funding events Use the funding events API to search and filter: ```bash theme={null} curl -X GET "https://sandbox.straddle.com/v1/funding_events?\ created_from=2024-10-01&\ created_to=2024-10-31&\ direction=deposit&\ event_type=charge_deposit" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Search parameters | Parameter | Description | Example | | - | - | - | | `created_from` | Start date (YYYY-MM-DD) | `2024-10-01` | | `created_to` | End date (YYYY-MM-DD) | `2024-10-31` | | `direction` | Filter by direction | `deposit`, `withdrawal` | | `event_type` | Filter by type | `charge_deposit` | | `trace_number` | Find by trace number | `071000301234567` | | `sort_by` | Sort field | `transfer_date`, `amount`, `id` | | `sort_order` | Sort direction | `asc`, `desc` | ## Getting funding event details Retrieve individual funding event with payment details: ```bash theme={null} curl -X GET https://sandbox.straddle.com/v1/funding_events/{id} \ -H "Authorization: Bearer YOUR_API_KEY" ``` This returns the funding event with associated payment IDs for detailed reconciliation. ## Reconciliation workflows ### Daily reconciliation ```javascript theme={null} async function dailyReconciliation(date) { // Get all funding events for the date const fundingEvents = await straddle.fundingEvents.list({ created_from: date, created_to: date }); for (const event of fundingEvents.data) { // Get detailed payment information const details = await straddle.fundingEvents.retrieve(event.id); // Match against your records using the funding event id. // This id appears in the ACH addenda record on your bank statement, // making it the reliable key for programmatic reconciliation. await reconcile({ fundingEventId: event.id, // primary reconciliation key amount: event.amount, direction: event.direction, type: event.event_type, paymentCount: event.payment_count, transferDate: event.transfer_date, traceNumber: event.trace_number // backup: not guaranteed on all bank statements }); // Update your ledger await updateLedger(event); } } ``` ### Matching payments to funding events Charges and payouts include `funding_ids` array: ```javascript theme={null} async function matchPaymentToFunding(chargeId) { // Get charge details const charge = await straddle.charges.retrieve(chargeId); // Check funding IDs if (charge.funding_ids && charge.funding_ids.length > 0) { for (const fundingId of charge.funding_ids) { const fundingEvent = await straddle.fundingEvents.retrieve(fundingId); console.log(`Charge ${chargeId} settled in funding event ${fundingId}`); console.log(`Settlement date: ${fundingEvent.transfer_date}`); console.log(`Trace number: ${fundingEvent.trace_number}`); } } else { console.log(`Charge ${chargeId} not yet funded`); } } ``` ### Handling reversals Track both original deposits and subsequent reversals: ```javascript theme={null} async function handleChargeReversal(chargeId) { const charge = await straddle.charges.retrieve(chargeId); if (charge.status === 'reversed') { // Find original deposit const originalDeposit = charge.funding_ids[0]; // Look for reversal funding event const reversalEvents = await straddle.fundingEvents.list({ event_type: 'charge_reversal', created_from: charge.updated_at.split('T')[0] }); // Match and update records for (const reversal of reversalEvents.data) { // Update your ledger for the reversal await recordReversal({ originalChargeId: chargeId, originalFundingId: originalDeposit, reversalFundingId: reversal.id, amount: reversal.amount, date: reversal.transfer_date }); } } } ``` ## Common patterns ### End-of-day settlement report ```javascript theme={null} async function generateSettlementReport(date) { const fundingEvents = await straddle.fundingEvents.list({ transfer_date: date, sort_by: 'event_type' }); const report = { date, summary: { charge_deposits: { count: 0, amount: 0 }, charge_reversals: { count: 0, amount: 0 }, payout_withdrawals: { count: 0, amount: 0 }, payout_returns: { count: 0, amount: 0 } }, events: [] }; for (const event of fundingEvents.data) { report.summary[event.event_type].count++; report.summary[event.event_type].amount += event.amount; report.events.push(event); } report.netSettlement = report.summary.charge_deposits.amount + report.summary.payout_returns.amount - report.summary.charge_reversals.amount - report.summary.payout_withdrawals.amount; return report; } ``` ## Best practices Reconcile funding events daily against your bank statements Use the funding event `id` as the primary key for bank statement reconciliation. It appears in the ACH addenda record and maps directly to the Straddle API response. Set up alerts for charge reversals to handle returns promptly Account for business day delays in settlement calculations ## Troubleshooting ### Missing funding events If expected funding events are missing: 1. **Check payment status** - Only `paid` charges create deposits 2. **Verify business days** - Weekends and holidays delay funding 3. **Review cutoff times** - Late payments may settle next day 4. **Check for holds** - Compliance holds can delay funding ### Reconciliation mismatches Common causes of discrepancies: * **Timing differences** - Effective date vs transfer date * **Bundled payments** - Multiple charges in one funding event * **Returns/reversals** - Original deposit and reversal are separate events * **Fee deductions** - Platform fees may be netted (if applicable) ## Next steps Funding events endpoint documentation Advanced reporting and searches Set up funding event notifications Test funding flows in sandbox # Payments overview Source: https://docs.straddle.com/guides/payments/overview Learn how charges, payouts, and funding events work together in Straddle to power ACH bank payments, settlements, and reconciliation for your platform. Straddle's payment system provides a unified API for moving money between your platform and your customers' bank accounts. This guide covers the core concepts and workflows for processing payments through Straddle. Before processing payments, you'll need to have [verified customers](/guides/identity/customers) and [connected bank accounts](/guides/bridge/overview) set up through Straddle's Identity and Bridge services. ## Core payment concepts Straddle organizes payment operations into three primary concepts: Collect money from your customers' bank accounts Send money to your customers' bank accounts Track money movement between Straddle and your business ### Understanding the flow When you process payments through Straddle: 1. **Charges** pull money from customer accounts into Straddle's network 2. **Payouts** push money from Straddle's network to customer accounts 3. **Funding Events** represent the settlement of these transactions to your business bank account ## Payment rails Straddle automatically optimizes payment routing across multiple rails to balance speed, cost, and reliability. You don't need to specify which rail to use. Straddle selects the optimal option automatically: **Processing Time**: 1-3 business days **Use Cases**: * Standard recurring payments * High-value transactions * Batch processing **Characteristics**: * Lower cost per transaction * Higher daily limits * Reversible for up to 60 days **Processing Time**: Seconds **Use Cases**: * Instant disbursements * Time-sensitive payments * Enhanced customer experience **Characteristics**: * 24/7/365 availability * Irrevocable once completed * Maximum \$1 million per transaction **Processing Time**: Seconds **Use Cases**: * Government payments * Instant settlement needs * Critical payment flows **Characteristics**: * Federal Reserve operated * 24/7/365 availability * Enhanced security and compliance **Processing Time**: Same business day **Use Cases**: * Urgent business payments * Payroll disbursements * Time-sensitive refunds **Characteristics**: * Multiple processing windows daily * Business days only * Higher limits than standard ACH ## Quick start example Here's a complete payment flow from customer creation to fund settlement: First, onboard your customer through Straddle's Identity service: ```bash theme={null} curl --request POST \ --header 'Authorization: Bearer YOUR_SECRET_API_KEY' \ --url https://sandbox.straddle.com/v1/customers \ --header 'Content-Type: application/json' \ --data '{ "name": "Ron Swanson", "type": "individual", "email": "user@example.com", "phone": "+12128675309", "device": { "ip_address": "192.168.1.1" } }' ``` Use Bridge to securely link the customer's bank account and generate a paykey: ```bash theme={null} curl --request POST \ --header 'Authorization: Bearer YOUR_SECRET_API_KEY' \ --url https://sandbox.straddle.com/v1/bridge/plaid \ --header 'Content-Type: application/json' \ --data '{ "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "plaid_token": "" }' ``` This returns a session for the customer to complete bank authentication, resulting in a `paykey`. Use the paykey to charge the customer: ```bash theme={null} curl --request POST \ --header 'Authorization: Bearer YOUR_SECRET_API_KEY' \ --url https://sandbox.straddle.com/v1/charges \ --header 'Content-Type: application/json' \ --data '{ "paykey": "", "description": "Monthly subscription fee", "amount": "10000", "currency": "", "payment_date": "2019-12-27", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "", "config": { "balance_check": "required" } }' ``` All fields shown are required. See the [charges guide](/guides/payments/charges) for complete parameter documentation. Track the charge status through [webhooks](/webhooks/overview/events): * `created` → Payment initiated * `scheduled` → Queued for processing * `pending` → Sent to payment network * `paid` → Successfully completed See [payment statuses](/guides/payments/statuses) for complete lifecycle details. View the corresponding funding event once the payment settles: ```bash theme={null} curl -X GET https://api.straddle.com/v1/funding?charge_id=ch_abc123 \ -H "Authorization: Bearer YOUR_API_KEY" ``` Learn more about [funding and reconciliation](/guides/payments/funding). ## Payment security Straddle implements multiple layers of security for payment processing: Real-time fraud detection and risk scoring on every transaction Optional pre-transaction balance checks to reduce NSF returns Configurable limits on transaction amounts and frequency Ability to pause suspicious transactions for manual review ## Common workflows ### Recurring subscriptions Process regular charges using stored paykeys: * Store customer paykeys after initial authentication * Create charges on your billing schedule * Handle failures and retries automatically * Update payment methods when needed ### Marketplace payouts Distribute funds to your sellers or service providers: * Verify recipient identity and bank accounts * Create payouts with detailed descriptions * Track payout status and handle failures * Reconcile platform fees and net settlements ### Instant transfers Provide immediate fund availability: * Use RTP rail for sub-second processing * Verify account eligibility for instant payments * Handle fallback to standard ACH if needed * Communicate clear timing to customers ## Testing payments Straddle provides comprehensive sandbox testing capabilities: * **Deterministic outcomes** - Control payment success/failure scenarios * **Accelerated processing** - Payments process in minutes instead of days * **Webhook simulation** - Test your event handling logic * **Error scenarios** - Simulate NSF, closed accounts, and returns See [sandbox testing guide](/guides/resources/sandbox-paybybank) for detailed examples. ## Next steps Learn to collect payments from customers Understand disbursing funds to customers Master payment lifecycles and status flows Explore the complete API documentation # Payouts: send funds to bank accounts Source: https://docs.straddle.com/guides/payments/payouts Use Straddle payouts to send ACH disbursements, refunds, and marketplace settlements to customer bank accounts with multi-rail processing and tracking. Payouts are credit transactions that push funds to a customer's bank account. Unlike charges, which pull funds from customers, payouts require Straddle to withdraw funds from your account before sending them to recipients. This distinction affects both funding timing and cancellation windows. ## What you'll learn This guide provides complete coverage of the payout workflow: * Creating payouts with proper authentication and device tracking * Understanding the payout status lifecycle and the critical `pending` threshold * Managing payouts through updates, holds, and cancellations before network submission * Handling payout-specific failures like recipient refusals and frozen accounts * Working with multiple payment rails (ACH, Same Day ACH, RTP, FedNow) * Testing payout scenarios using sandbox outcomes Use payouts for marketplace settlements, refunds, rewards, disbursements, or withdrawals: any scenario where you need to send money to verified bank accounts. Payouts require a `paykey`: a token representing a verified bank account. Learn about connecting bank accounts in the [Bridge guide](/guides/bridge/overview). ## The payout object A payout represents a credit transaction with comprehensive status tracking and metadata: ```json theme={null} { "id": "po_abc123def", "paykey": "pk_xyz789abc", "amount": 25000, "currency": "USD", "description": "Marketplace payout - October sales", "payment_date": "2024-10-15", "status": "paid", "status_details": { "message": "Payout successfully completed", "reason": "ok", "source": "system", "code": null, "changed_at": "2024-10-16T09:00:00Z" }, "external_id": "payout_789", "device": { "ip_address": "192.168.1.1" }, "config": { "sandbox_outcome": null }, "metadata": { "seller_id": "seller_123", "period": "2024-10" }, "payment_rail": "ACH", "paykey_details": { "bank_name": "Wells Fargo", "last4": "4321", "account_type": "checking" }, "customer_details": { "name": "Jane Smith", "email": "jane@example.com" }, "trace_number": "071000301234568", "funding_ids": ["fe_def456"], "status_history": [...], "created_at": "2024-10-15T10:00:00Z", "updated_at": "2024-10-16T09:00:00Z", "processed_at": "2024-10-15T14:00:00Z" } ``` ### Core fields | Field | Type | Description | | - | - | - | | `id` | string | Unique payout identifier | | `paykey` | string | Token for recipient's bank account | | `amount` | integer | Amount in cents (25000 = \$250.00) | | `currency` | string | Currency code (USD only) | | `description` | string | Statement descriptor | | `payment_date` | string | Processing date (YYYY-MM-DD) | | `status` | string | Current payment status | | `status_details` | object | Detailed status information | | `external_id` | string | Your unique reference | | `processed_at` | string | When sent to payment network | | `trace_number` | string | ACH network tracking number | | `funding_ids` | array | Related funding events | ## Creating a payout All payouts require these fields. For a complete list of fields, visit the [Payouts API reference](/api-reference/payouts/create). ```bash cURL theme={null} curl -X POST https://sandbox.straddle.com/v1/payouts \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paykey": "pk_xyz789abc", "amount": 25000, "currency": "USD", "description": "Marketplace payout - October sales", "payment_date": "2024-10-15", "device": { "ip_address": "192.168.1.1" }, "external_id": "payout_789" }' ``` ```javascript Node.js theme={null} const payout = await straddle.payouts.create({ paykey: "pk_xyz789abc", amount: 25000, currency: "USD", description: "Marketplace payout - October sales", payment_date: "2024-10-15", device: { ip_address: "192.168.1.1" }, external_id: "payout_789" }); ``` ```python Python theme={null} payout = straddle.payouts.create( paykey="pk_xyz789abc", amount=25000, currency="USD", description="Marketplace payout - October sales", payment_date="2024-10-15", device={ "ip_address": "192.168.1.1" }, external_id="payout_789" ) ``` ```json 201 Created theme={null} { "meta": { "api_request_id": "3a2b1c4d-0e6f-4a88-9876-123456abcdef", "api_request_timestamp": "2024-10-15T10:00:00Z" }, "response_type": "object", "data": { "id": "po_abc123def", "paykey": "pk_xyz789abc", "amount": 25000, "currency": "USD", "description": "Marketplace payout - October sales", "payment_date": "2024-10-15", "status": "created", "status_details": { "message": "Payout successfully created and awaiting validation.", "reason": "ok", "source": "system", "changed_at": "2024-10-15T10:00:00Z" }, "external_id": "payout_789", "device": { "ip_address": "192.168.1.1" }, "config": {}, "metadata": {}, "created_at": "2024-10-15T10:00:00Z", "updated_at": "2024-10-15T10:00:00Z" } } ``` ```json 400 Bad Request theme={null} { "meta": { "api_request_id": "f1b1b1b1-1b1b-1b1b-1b1b-1b1b1b1b1b1b" }, "response_type": "error", "error": { "status": 400, "type": "validation_error", "title": "Invalid Input Data", "detail": "The request contains invalid field values.", "items": [ { "reference": "paykey", "detail": "The provided paykey is invalid or expired." } ] } } ``` ## Required parameters Payment key for the recipient's verified bank account. Obtained via Bridge flow. Amount to send in cents. Must be positive. Example: `25000` for \$250.00 ISO 4217 currency code. Currently only `"USD"` is supported. Description appearing on bank statements. Maximum 80 characters. Be clear and recognizable. Date to process payment (YYYY-MM-DD). Can be today or future-dated up to 90 days. Device information for compliance tracking. IP address when payout was authorized. Use `"0.0.0.0"` for server-initiated payouts. Your unique identifier for this payout. Must be unique across all payouts. Used for idempotency. ## Optional parameters Processing configuration options. For testing only. Simulates specific outcomes in sandbox environment. Custom key-value pairs. Maximum 20 keys, 40 characters per key/value. ## Payment status lifecycle Payouts progress through the same statuses as charges: | Status | Description | Can Modify? | | - | - | - | | `created` | Initial state, awaiting verification | ✅ Yes | | `scheduled` | Verified and queued for processing | ✅ Yes | | `pending` | Sent to payment network | ❌ No | | `paid` | Successfully completed | ❌ No | | `failed` | Declined before completion | ❌ Terminal | | `reversed` | Returned after completion | ❌ Terminal | | `cancelled` | Stopped before network submission | ❌ Terminal | | `on_hold` | Paused for review | ⚠️ Depends | **Critical**: Once a payout reaches `pending` status, it has been submitted to the payment network and CANNOT be stopped, held, or cancelled. **Important Distinction**: Unlike charges which pull funds, payouts require Straddle to withdraw funds from your account BEFORE sending them to recipients. This affects funding event timing. ### Status details Every status change includes detailed information: ```json theme={null} "status_details": { "message": "Payout failed - recipient refused the payment", "reason": "payout_refused", "source": "bank_decline", "code": "R23", "changed_at": "2024-10-16T14:30:00Z" } ``` ### Payout-specific failure reasons | Reason | Description | Source | | - | - | - | | `payout_refused` | Recipient declined the credit | `bank_decline` | | `invalid_routing` | Routing number doesn't accept credits | `bank_decline` | | `frozen_bank_account` | Recipient account frozen | `bank_decline` | | `risk_review` | AML/compliance review required | `watchtower` | | `amount_too_large` | Exceeds payout limits | `system` | For complete status details, see [Payment Statuses Guide](/guides/payments/statuses). ## Common operations ### [Retrieve a payout](/api-reference/payouts/retrieve) ```bash theme={null} curl -X GET https://sandbox.straddle.com/v1/payouts/{payout_id} \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### [Update a payout](/api-reference/payouts/update) Update payouts in `created` or `scheduled` status: ```bash theme={null} curl -X PUT https://sandbox.straddle.com/v1/payouts/{payout_id} \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 30000, "description": "Updated payout amount" }' ``` ### [Cancel a payout](/api-reference/payouts/cancel) Cancel payouts before they reach `pending` status: ```bash theme={null} curl -X POST https://sandbox.straddle.com/v1/payouts/{payout_id}/cancel \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Seller verification failed" }' ``` ### [Place on hold](/api-reference/payouts/hold) Pause a payout for review (only in `created` or `scheduled` status): ```bash theme={null} curl -X POST https://sandbox.straddle.com/v1/payouts/{payout_id}/hold \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Awaiting seller verification" }' ``` ### [Release a hold](/api-reference/payouts/release) Release user-initiated holds only: ```bash theme={null} curl -X POST https://sandbox.straddle.com/v1/payouts/{payout_id}/release \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason": "Seller verified" }' ``` Compliance holds (`watchtower` source) cannot be released via API. They require manual review in the dashboard. ### Resubmit a payout [Re-attempt](/guides/payments/statuses#resubmit-failed-payments) a payout using the [resubmit](https://straddle.dev/api-reference#tag/payout/POST/v1/payouts/\{id}/resubmit) endpoint. This creates a new transaction that inherits the original payment's details. ```shellscript theme={null} curl -X POST https://api.straddle.com/v1/payouts/{id}/resubmit \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "payment_date": "2026-03-01", "description": "Retry the payout", "external_id": "my-custom-external-id" }' ``` ## Payment rails Straddle automatically selects the optimal payment rail based on amount, timing, and availability: | Rail | Speed | Availability | Typical Use | | - | - | - | - | | ACH | 1 business day | Business days | Standard payouts | | Same Day ACH | Same business day | Business days | Standard payouts | | RTP | Seconds | 24/7/365 | Instant payouts | | FedNow | Seconds | 24/7/365 | Instant payouts | Straddle automatically optimizes rail selection. You don't need to specify which rail to use. Straddle selects the fastest, most cost-effective option available. ## Handling failures When payouts fail, check `status_details` for specific information: ```javascript theme={null} if (payout.status === 'failed') { switch(payout.status_details.reason) { case 'payout_refused': // Recipient declined - investigate break; case 'invalid_bank_account': // Request updated bank details break; case 'frozen_bank_account': // Cannot retry - handle specially break; case 'risk_review': // Compliance review needed break; case 'amount_too_large': // Split into smaller payouts break; } } ``` ## Testing in sandbox Use `sandbox_outcome` in the config to simulate scenarios: ```json theme={null} { "paykey": "pk_test456", "amount": 15000, "config": { "sandbox_outcome": "paid" // or "failed_closed_bank_account", etc. } // ... other required fields } ``` Common test scenarios: * `"paid"` - Successful payout * `"failed_closed_bank_account"` - Account closed * `"on_hold_daily_limit"` - Compliance hold * `"failed_payout_refused"` - Recipient refusal ## Webhooks Set up [webhooks](/webhooks/overview/101) to receive real-time payout updates: ```javascript theme={null} app.post('/webhooks/straddle', (req, res) => { const event = req.body; switch(event.type) { case 'payout.created': // New payout created break; case 'payout.paid': // Payout successful - update records break; case 'payout.failed': // Check status_details.reason break; case 'payout.on_hold': // Check if compliance hold if (event.data.status_details.source === 'watchtower') { // Notify compliance team } break; } res.status(200).send('OK'); }); ``` ## Best practices Always include a unique `external_id` to prevent duplicate payouts Confirm recipient details before large payouts Track daily/monthly payout volumes against limits Implement workflows for rare payout returns ## Next steps Complete payout endpoint documentation Detailed status flows and return codes Learn about collecting payments Understand settlement and money movement # Reporting and exporting payment data Source: https://docs.straddle.com/guides/payments/reports Search, filter, and export Straddle payment data using the API and dashboard for reporting, reconciliation, and accounting workflows in your platform. The payments search API provides powerful capabilities to query, filter, and analyze both charges and payouts in a unified interface. With over 20 search parameters and support for complex filtering, you can build everything from real-time dashboards to detailed reconciliation reports that match your exact business requirements. ## What you'll build with this guide This guide equips you with patterns and code examples for: * **Unified payment searches**: Query charges and payouts together or separately * **Advanced filtering**: Combine date ranges, amounts, statuses, and metadata for precise results * **Reconciliation workflows**: Match funding events to bank statements using the funding event ID from the ACH addenda record * **Return tracking**: Analyze reversed payments and identify high-risk patterns * **Export capabilities**: Generate CSV and JSON reports for accounting systems * **Performance monitoring**: Build real-time metrics and anomaly detection * **Pagination strategies**: Efficiently process large datasets with parallel requests Whether you need daily settlement reports, customer payment histories, or failure analysis, this guide provides production-ready patterns for every reporting scenario. ## Unified payment search The payments search endpoint allows you to query both charges and payouts together or separately, providing a complete view of money movement through your platform. ### Basic search Search for all payments in a date range: ```bash theme={null} curl -X GET "https://sandbox.straddle.com/v1/payments/search?\ created_from=2024-10-01&\ created_to=2024-10-31" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Response includes both charges and payouts: ```json theme={null} { "data": [ { "id": "ch_abc123", "payment_type": "charge", "amount": 10000, "status": "paid", "created_at": "2024-10-15T10:00:00Z" }, { "id": "po_def456", "payment_type": "payout", "amount": 25000, "status": "paid", "created_at": "2024-10-16T14:00:00Z" } ], "pagination": { "current_page": 1, "total_pages": 5, "total_count": 247 } } ``` ## Search parameters ### Date filters | Parameter | Description | Format | Example | | - | - | - | - | | `created_from` | Start of creation date range | YYYY-MM-DD | `2024-10-01` | | `created_to` | End of creation date range | YYYY-MM-DD | `2024-10-31` | | `updated_from` | Start of update date range | YYYY-MM-DD | `2024-10-01` | | `updated_to` | End of update date range | YYYY-MM-DD | `2024-10-31` | | `payment_date_from` | Start of payment date range | YYYY-MM-DD | `2024-10-01` | | `payment_date_to` | End of payment date range | YYYY-MM-DD | `2024-10-31` | ### Payment filters | Parameter | Description | Values | Example | | - | - | - | - | | `payment_type` | Filter by type | `charge`, `payout` | `charge` | | `status` | Filter by status | `created`, `scheduled`, `pending`, `paid`, `failed`, `reversed`, `cancelled`, `on_hold` | `paid` | | `status_reason` | Filter by failure reason | `insufficient_funds`, `closed_bank_account`, etc. | `insufficient_funds` | | `amount_min` | Minimum amount in cents | Integer | `10000` | | `amount_max` | Maximum amount in cents | Integer | `500000` | ### Reference filters | Parameter | Description | Example | | - | - | - | | `paykey` | Filter by paykey | `pk_abc123xyz` | | `external_id` | Your reference ID | `inv_12345` | | `customer_id` | Customer identifier | `cust_789` | | `payment_id` | Specific payment ID | `ch_def456` | | `trace_number` | ACH trace number | `071000301234567` | ### Pagination & sorting | Parameter | Description | Default | Values | | - | - | - | - | | `page` | Page number | `1` | Integer | | `limit` | Results per page | `100` | 1-500 | | `sort_by` | Sort field | `created_at` | `created_at`, `updated_at`, `amount`, `payment_date` | | `sort_order` | Sort direction | `desc` | `asc`, `desc` | ## Common search patterns ### Daily settlement report Get all successful payments for settlement reconciliation: ```javascript theme={null} async function getDailySettlement(date) { const payments = await straddle.payments.search({ payment_date_from: date, payment_date_to: date, status: 'paid', sort_by: 'payment_type' }); const summary = { date, charges: { count: 0, amount: 0 }, payouts: { count: 0, amount: 0 }, net: 0 }; for (const payment of payments.data) { if (payment.payment_type === 'charge') { summary.charges.count++; summary.charges.amount += payment.amount; } else { summary.payouts.count++; summary.payouts.amount += payment.amount; } } summary.net = summary.charges.amount - summary.payouts.amount; return summary; } ``` ### Failed payment analysis Identify failure patterns for risk optimization: ```javascript theme={null} async function analyzeFailures(startDate, endDate) { const failures = await straddle.payments.search({ created_from: startDate, created_to: endDate, status: 'failed', limit: 500 }); // Group by failure reason const reasonAnalysis = {}; for (const payment of failures.data) { const reason = payment.status_details.reason; if (!reasonAnalysis[reason]) { reasonAnalysis[reason] = { count: 0, total_amount: 0, payment_types: { charge: 0, payout: 0 } }; } reasonAnalysis[reason].count++; reasonAnalysis[reason].total_amount += payment.amount; reasonAnalysis[reason].payment_types[payment.payment_type]++; } return { period: { from: startDate, to: endDate }, total_failures: failures.pagination.total_count, by_reason: reasonAnalysis }; } ``` ### Customer payment history View all payments for a specific customer: ```javascript theme={null} async function getCustomerPaymentHistory(customerId, paykey) { const payments = await straddle.payments.search({ paykey: paykey, sort_by: 'created_at', sort_order: 'desc', limit: 100 }); return { customer_id: customerId, paykey: paykey, total_payments: payments.pagination.total_count, recent_payments: payments.data.map(p => ({ id: p.id, type: p.payment_type, amount: p.amount, status: p.status, date: p.created_at, description: p.description })) }; } ``` ## Advanced filtering ### Multi-status search Find payments in specific states: ```bash theme={null} curl -X GET "https://api.straddle.com/v1/payments/search?\ status=pending&\ status=scheduled&\ payment_type=charge" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Amount range filtering Find high-value transactions: ```bash theme={null} curl -X GET "https://api.straddle.com/v1/payments/search?\ amount_min=100000&\ amount_max=1000000&\ created_from=2024-10-01" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Metadata search Search using your custom metadata: ```javascript theme={null} async function searchByMetadata(key, value) { const payments = await straddle.payments.search({ [`metadata.${key}`]: value }); return payments.data; } // Example: Find all payments for a specific order const orderPayments = await searchByMetadata('order_id', 'ord_789'); ``` ## Reconciliation workflows ### Bank statement reconciliation Match funding events to bank transactions using the funding event `id`. Each funding event produces a single ACH transfer; the ACH addenda record on that transfer contains the funding event `id` and a description (e.g., `charge deposit`, `payout withdrawal`). Your bank surfaces this in the transaction detail, giving you a direct, programmatic link back to the Straddle API. ```javascript theme={null} async function reconcileBankStatement(statementDate, bankTransactions) { // Get funding events created around the statement date. // Each entry in bankTransactions is expected to include an `addendaId` field // parsed from the ACH addenda record on the bank statement. // Note: the API filters by created_at, not transfer_date. Funding events are // typically created one business day before the transfer_date, so widen the // range slightly if your statement date falls on a Monday or after a holiday. const fundingEvents = await straddle.fundingEvents.list({ created_from: statementDate, created_to: statementDate }); const reconciliation = { date: statementDate, matched: [], unmatched_funding: [], unmatched_bank: [...bankTransactions] }; // Primary match: funding event id from the ACH addenda record. for (const event of fundingEvents.data) { const bankIndex = reconciliation.unmatched_bank.findIndex( t => t.addendaId === event.id ); if (bankIndex !== -1) { reconciliation.matched.push({ funding_event_id: event.id, event_type: event.event_type, bank_transaction: reconciliation.unmatched_bank[bankIndex], amount: event.amount }); reconciliation.unmatched_bank.splice(bankIndex, 1); } else { // Fallback: match by trace number if the bank does not surface the addenda id. const traceIndex = reconciliation.unmatched_bank.findIndex( t => t.trace === event.trace_number ); if (traceIndex !== -1) { reconciliation.matched.push({ funding_event_id: event.id, event_type: event.event_type, bank_transaction: reconciliation.unmatched_bank[traceIndex], amount: event.amount, matched_by: 'trace_number' }); reconciliation.unmatched_bank.splice(traceIndex, 1); } else { reconciliation.unmatched_funding.push(event); } } } return reconciliation; } ``` ### Return tracking Monitor and analyze returned payments: ```javascript theme={null} async function trackReturns(startDate, endDate) { // Get all reversed payments const reversed = await straddle.payments.search({ created_from: startDate, created_to: endDate, status: 'reversed' }); const returnAnalysis = { period: { from: startDate, to: endDate }, total_returns: reversed.pagination.total_count, by_code: {}, by_day: {}, high_risk_paykeys: [] }; // Analyze return patterns for (const payment of reversed.data) { const code = payment.status_details.code; const date = payment.updated_at.split('T')[0]; // Track by return code if (!returnAnalysis.by_code[code]) { returnAnalysis.by_code[code] = { count: 0, amount: 0 }; } returnAnalysis.by_code[code].count++; returnAnalysis.by_code[code].amount += payment.amount; // Track by day if (!returnAnalysis.by_day[date]) { returnAnalysis.by_day[date] = { count: 0, amount: 0 }; } returnAnalysis.by_day[date].count++; returnAnalysis.by_day[date].amount += payment.amount; } // Identify high-risk paykeys const paykeyReturns = {}; for (const payment of reversed.data) { if (!paykeyReturns[payment.paykey]) { paykeyReturns[payment.paykey] = 0; } paykeyReturns[payment.paykey]++; } returnAnalysis.high_risk_paykeys = Object.entries(paykeyReturns) .filter(([_, count]) => count > 2) .map(([paykey, count]) => ({ paykey, return_count: count })) .sort((a, b) => b.return_count - a.return_count); return returnAnalysis; } ``` ## Export patterns ### CSV export Generate CSV reports for accounting: ```javascript theme={null} async function exportPaymentsCSV(startDate, endDate) { const payments = await straddle.payments.search({ created_from: startDate, created_to: endDate, limit: 500 // Process in batches for large exports }); const csv = [ // Headers 'ID,Type,Amount,Status,Created,Updated,Description,External ID,Trace Number' ]; for (const payment of payments.data) { csv.push([ payment.id, payment.payment_type, payment.amount / 100, // Convert to dollars payment.status, payment.created_at, payment.updated_at, `"${payment.description}"`, // Quote for commas payment.external_id || '', payment.trace_number || '' ].join(',')); } return csv.join('\n'); } ``` ### JSON export with details Export complete payment data: ```javascript theme={null} async function exportDetailedPayments(filters) { const allPayments = []; let page = 1; let hasMore = true; while (hasMore) { const result = await straddle.payments.search({ ...filters, page, limit: 100 }); // Enrich with full details for (const payment of result.data) { const detailed = payment.payment_type === 'charge' ? await straddle.charges.retrieve(payment.id) : await straddle.payouts.retrieve(payment.id); allPayments.push(detailed); } hasMore = page < result.pagination.total_pages; page++; } return { export_date: new Date().toISOString(), filters, total_count: allPayments.length, payments: allPayments }; } ``` ## Monitoring & alerts ### Real-time monitoring Track payment metrics in real-time: ```javascript theme={null} async function getPaymentMetrics() { const today = new Date().toISOString().split('T')[0]; // Today's activity const todayPayments = await straddle.payments.search({ created_from: today, created_to: today }); // Pending payments const pending = await straddle.payments.search({ status: 'pending' }); // Recent failures const failures = await straddle.payments.search({ status: 'failed', created_from: today, created_to: today }); return { timestamp: new Date().toISOString(), today: { total_count: todayPayments.pagination.total_count, total_volume: todayPayments.data.reduce((sum, p) => sum + p.amount, 0) }, pending: { count: pending.pagination.total_count, volume: pending.data.reduce((sum, p) => sum + p.amount, 0) }, failures: { count: failures.pagination.total_count, primary_reason: getMostCommonReason(failures.data) } }; } ``` ### Anomaly detection Identify unusual payment patterns: ```javascript theme={null} async function detectAnomalies(lookbackDays = 7) { const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - lookbackDays); const payments = await straddle.payments.search({ created_from: startDate.toISOString().split('T')[0], created_to: endDate.toISOString().split('T')[0] }); const anomalies = []; // Large transaction detection const avgAmount = payments.data.reduce((sum, p) => sum + p.amount, 0) / payments.data.length; const largeTransactions = payments.data.filter(p => p.amount > avgAmount * 5); if (largeTransactions.length > 0) { anomalies.push({ type: 'large_transactions', count: largeTransactions.length, payments: largeTransactions.map(p => p.id) }); } // Velocity check - too many payments from same paykey const paykeyVelocity = {}; for (const payment of payments.data) { if (!paykeyVelocity[payment.paykey]) { paykeyVelocity[payment.paykey] = []; } paykeyVelocity[payment.paykey].push(payment); } for (const [paykey, payments] of Object.entries(paykeyVelocity)) { if (payments.length > 10) { // More than 10 payments in period anomalies.push({ type: 'high_velocity', paykey, count: payments.length, total_amount: payments.reduce((sum, p) => sum + p.amount, 0) }); } } // Unusual failure rate const failureRate = payments.data.filter(p => p.status === 'failed').length / payments.data.length; if (failureRate > 0.15) { // More than 15% failure rate anomalies.push({ type: 'high_failure_rate', rate: failureRate, message: `${(failureRate * 100).toFixed(1)}% failure rate detected` }); } return anomalies; } ``` ## Pagination strategies ### Cursor-based iteration Process large result sets efficiently: ```javascript theme={null} async function* iterateAllPayments(filters) { let page = 1; let hasMore = true; while (hasMore) { const result = await straddle.payments.search({ ...filters, page, limit: 100 }); for (const payment of result.data) { yield payment; } hasMore = page < result.pagination.total_pages; page++; // Rate limiting await new Promise(resolve => setTimeout(resolve, 100)); } } // Usage async function processAllPayments() { for await (const payment of iterateAllPayments({ status: 'paid' })) { await processPayment(payment); } } ``` ### Parallel processing Speed up large exports with parallel requests: ```javascript theme={null} async function parallelExport(filters) { // First, get total count const initial = await straddle.payments.search({ ...filters, limit: 1 }); const totalPages = initial.pagination.total_pages; const batchSize = 5; // Process 5 pages at a time const allPayments = []; for (let i = 1; i <= totalPages; i += batchSize) { const pagePromises = []; for (let page = i; page < Math.min(i + batchSize, totalPages + 1); page++) { pagePromises.push( straddle.payments.search({ ...filters, page, limit: 100 }) ); } const results = await Promise.all(pagePromises); for (const result of results) { allPayments.push(...result.data); } } return allPayments; } ``` ## Performance optimization ### Efficient date ranges For better performance, use specific date ranges rather than open-ended queries. The API performs best with date ranges under 90 days. ```javascript theme={null} // Good - Specific date range const efficient = await straddle.payments.search({ created_from: '2024-10-01', created_to: '2024-10-31' }); // Less efficient - Open-ended const lessEfficient = await straddle.payments.search({ created_from: '2024-01-01' // No end date }); ``` ### Index-friendly filters Use indexed fields for faster queries: ```javascript theme={null} // Fast - Uses indexed fields const fast = await straddle.payments.search({ payment_id: 'ch_abc123', // Direct ID lookup paykey: 'pk_xyz789', // Indexed field status: 'paid' // Indexed enum }); // Slower - Requires scanning const slower = await straddle.payments.search({ 'metadata.custom_field': 'value' // Not indexed }); ``` ## Common use cases ### Monthly billing report ```javascript theme={null} async function generateMonthlyReport(year, month) { const startDate = `${year}-${String(month).padStart(2, '0')}-01`; const endDate = new Date(year, month, 0).toISOString().split('T')[0]; const report = { period: { year, month }, summary: { total_charges: 0, total_payouts: 0, net_revenue: 0, success_rate: 0 }, daily_breakdown: {}, top_customers: [], failure_analysis: {} }; // Get all payments for the month const payments = await straddle.payments.search({ created_from: startDate, created_to: endDate, limit: 500 }); // Process metrics let successful = 0; const customerTotals = {}; for (const payment of payments.data) { // Summary totals if (payment.payment_type === 'charge') { report.summary.total_charges += payment.amount; } else { report.summary.total_payouts += payment.amount; } // Success tracking if (payment.status === 'paid') { successful++; } // Daily breakdown const day = payment.created_at.split('T')[0]; if (!report.daily_breakdown[day]) { report.daily_breakdown[day] = { charges: 0, payouts: 0, count: 0 }; } report.daily_breakdown[day].count++; if (payment.payment_type === 'charge') { report.daily_breakdown[day].charges += payment.amount; } else { report.daily_breakdown[day].payouts += payment.amount; } // Track by customer if (!customerTotals[payment.paykey]) { customerTotals[payment.paykey] = 0; } customerTotals[payment.paykey] += payment.amount; } // Calculate final metrics report.summary.net_revenue = report.summary.total_charges - report.summary.total_payouts; report.summary.success_rate = (successful / payments.data.length) * 100; // Top customers report.top_customers = Object.entries(customerTotals) .sort(([,a], [,b]) => b - a) .slice(0, 10) .map(([paykey, total]) => ({ paykey, total })); return report; } ``` ## Best practices Always specify date ranges to improve query performance Use pagination for exports exceeding 100 records Cache search results that don't change frequently Implement rate limiting for bulk operations ## Troubleshooting ### Missing payments If payments aren't appearing in search results: 1. **Check date ranges** - Ensure dates include the payment creation time 2. **Verify filters** - Remove filters one by one to identify issues 3. **Check status** - Some statuses like `unknown` may not appear by default 4. **Review pagination** - Check if results are on subsequent pages ### Performance issues For slow queries: * Narrow date ranges to 30 days or less * Use specific IDs when possible * Avoid complex metadata queries * Implement caching for repeated searches ## Next steps Complete search endpoint documentation Real-time payment notifications Search and analyze funding events Settlement and reconciliation # Payment status and lifecycle reference Source: https://docs.straddle.com/guides/payments/statuses Reference for Straddle ACH payment status flows, transitions, status reasons, and return codes for charges, payouts, and funding events. Understanding payment statuses is critical for properly handling charges and payouts. Every payment moves through a defined lifecycle with specific status transitions. Knowing when payments can be modified, or when they become unstoppable, directly impacts your application's payment logic and user experience. ## What this reference covers This comprehensive guide provides everything you need to handle payment statuses correctly: * **Status lifecycles**: The complete flow from creation to terminal states * **The pending threshold**: Why `pending` status is the point of no return * **Failed vs reversed**: Critical distinction between pre-funding and post-funding failures * **ACH return codes**: All R-codes and S-codes with their meanings and timing * **Status reasons**: Complete catalog of failure reasons and their sources * **Status/Source/Reason matrix**: Valid combinations showing what actually occurs * **Implementation patterns**: Code examples for monitoring and handling status changes Whether you're building retry logic, handling disputes, or reconciling returns, this reference ensures you respond appropriately to every payment state. ## Payment lifecycle overview The happy path for payments follows this progression: Payment successfully created and awaiting verification Payment passed verifications and risk scoring, queued for processing **Payment sent to network - CANNOT BE STOPPED** Payment successfully funded **Critical Understanding:** Once a payment reaches `pending` status, it has been submitted to the payment network and cannot be stopped, held, or cancelled. The payment must complete its network processing. ## Status values ### Complete status reference | Status | Description | Can Modify? | Terminal? | | - | - | - | - | | `created` | Payment created, awaiting verification | ✅ | No | | `scheduled` | Verified and queued for processing | ✅ | No | | `pending` | Sent to network | ❌ | No | | `on_hold` | Paused for review | ✅\* | No | | `paid` | Successfully funded | ❌ | No† | | `failed` | Declined/returned **before** funding | ❌ | Yes | | `reversed` | Returned **after** funding completed | ❌ | Yes | | `cancelled` | Terminated before network submission | ❌ | Yes | \*Only user-initiated holds can be released by the user; Watchtower holds require Straddle authorization\ †Can still transition to `reversed` if return occurs post-funding ### Understanding failed vs reversed | Status | When It Occurs | Money Movement | Example | | - | - | - | - | | `failed` | Before funding completes | Funds deposited in your account | NSF during processing | | `reversed` | After funding completes | Funds deposited then withdrawn from your account | Dispute filed after payment | ## Status sources Sources identify where status changes originate: | Source | Description | When Used | | - | - | - | | `system` | Automated system processing | Normal status progression (created → scheduled → pending → paid) | | `watchtower` | Internal fraud/risk system | Balance checks, fraud screening, validation failures | | `bank_decline` | ACH network return | Returns from banks | | `customer_dispute` | Customer disputed with their bank | Unauthorized claims (R05, R07, R10, R11, R29) | | `user_action` | Manual action via API | User-initiated holds, cancels, releases | ## Status/source/reason matrix ### Success states | Status | Source | Reason | Context | | - | - | - | - | | `created` | `system` | `ok` | Payment created and awaiting verification | | `scheduled` | `system` | `ok` | Payment validated and scheduled | | `pending` | `system` | `ok` | Payment submitted to ACH network | | `paid` | `system` | `ok` | Payment successfully funded | ### Hold states | Status | Source | Reason | Context | | - | - | - | - | | `on_hold` | `watchtower` | `risk_review` | Flagged by risk system (paykey or customer under review) | | `on_hold` | `watchtower` | `amount_too_large` | Exceeds max transaction or daily limits | | `on_hold` | `user_action` | `user_request` | Manually held by user via API | ### Failed states (pre-funding) | Status | Source | Reason | Context | | - | - | - | - | | `failed` | `watchtower` | `insufficient_funds` | Pre-submission balance check detected insufficient funds | | `failed` | `watchtower` | `payment_blocked` | Blocked by Straddle fraud screening | | `failed` | `watchtower` | `invalid_paykey` | Paykey validation failed (blocked, restricted, or customer not found) | | `failed` | `watchtower` | `payment_stopped` | Payment rail assignment failed | | `failed` | `watchtower` | `duplicate_entry` | Duplicate payment detected during ID assignment | | `failed` | `bank_decline` | `insufficient_funds` | ACH return R01/R09 | | `failed` | `bank_decline` | `closed_bank_account` | ACH return R02 | | `failed` | `bank_decline` | `invalid_bank_account` | ACH return R03/R04/R20 | | `failed` | `bank_decline` | `invalid_routing` | ACH return R13 | | `failed` | `bank_decline` | `frozen_bank_account` | ACH return R16 | | `failed` | `bank_decline` | `owner_deceased` | ACH return R14/R15 | | `failed` | `bank_decline` | `payment_stopped` | ACH return R08 | | `failed` | `bank_decline` | `payout_refused` | ACH return R23 | | `failed` | `bank_decline` | `duplicate_entry` | ACH return R24 | | `failed` | `bank_decline` | `other_network_return` | Other ACH return codes | | `failed` | `customer_dispute` | `disputed` | ACH return R05/R07/R10/R11/R29 (before funding) | | `failed` | `user_action` | `user_request` | Manually failed by user via API | ### Reversed states (post-funding) | Status | Source | Reason | Context | | - | - | - | - | | `reversed` | `bank_decline` | `insufficient_funds` | Late ACH return R01/R09 | | `reversed` | `bank_decline` | `closed_bank_account` | Late ACH return R02 | | `reversed` | `bank_decline` | `invalid_bank_account` | Late ACH return R03/R04/R20 | | `reversed` | `bank_decline` | `invalid_routing` | Late ACH return R13 | | `reversed` | `bank_decline` | `frozen_bank_account` | Late ACH return R16 | | `reversed` | `bank_decline` | `owner_deceased` | Late ACH return R14/R15 | | `reversed` | `bank_decline` | `payment_stopped` | Late ACH return R08 | | `reversed` | `bank_decline` | `payout_refused` | Late ACH return R23 | | `reversed` | `bank_decline` | `duplicate_entry` | Late ACH return R24 | | `reversed` | `bank_decline` | `other_network_return` | Other late ACH returns | | `reversed` | `customer_dispute` | `disputed` | ACH return R05/R07/R10/R11/R29 (after funding) | ### Cancelled states | Status | Source | Reason | Context | | - | - | - | - | | `cancelled` | `user_action` | `user_request` | Manually cancelled by user via API | Cancellation only occurs via user action in the dashboard or API. ### Resubmit failed payments Retry any failed, reversed, or cancelled [charge](https://straddle.dev/api-reference#tag/charge/POST/v1/charges/\{id}/resubmit) or [payout](https://straddle.dev/api-reference#tag/payout/POST/v1/payouts/\{id}/resubmit) by creating a new payment linked to the original. The new payment carries over the original bank information and payment details. Optional: provide a new `payment_date`, `description`, or `external_id`. Otherwise, Straddle generates these from the original payment. The new payment inherits the `amount`, `paykey`, `currency`, and `metadata` from the original. Each payment can only be resubmitted once, but if a resubmitted payment also fails, resubmit that one to create a chain. Resubmit a charge with an updated payment date and description. ```shellscript theme={null} curl -X POST https://api.straddle.com/v1/charges/{id}/resubmit \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "payment_date": "2026-03-01", "description": "Customer requested retry after payday", "external_id": "my-custom-external-id" }' ``` ### Refund paid charges Return funds to a customer for a [paid charge](https://straddle.dev/api-reference#tag/charge/POST/v1/charges/\{id}/refund) directly from the dashboard or API. The refund is sent back to the customer's original bank account using the same paykey as the source charge, so there's no manual lookup or destination-account work. To issue a refund from the dashboard, see the [step-by-step walkthrough](https://help.straddle.com/article/how-to-refund-a-paid-charge-in-the-dashboard) in the help center. Each charge can be refunded once, full or partial. The refund amount must be greater than \$0 and no more than the original charge amount. When you create a refund: * A new payout is created with `payment_type: "payout"` and a description of `Refund for Charge ID: {id}`. If you supplied your own `description`, it's appended after the system prefix. * The original charge stays in **Paid** status. Refunds are tracked separately as payouts and linked through `related_payments`. * The new refund payout follows normal payout statuses (Pending → Paid). ```shellscript theme={null} curl -X POST https://api.straddle.com/v1/charges/{id}/refund \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 5000, "description": "Customer returned damaged item" }' ``` After a refund, the original charge's `related_payments` lists the new refund payout, and the refund payout's `related_payments` lists the source charge. Each entry includes the linked payment's `id`, `relationship`, and `payment_type`. Relationship values: * `original`: the linked payment is the source. Appears on the refund payout, pointing back to the charge. * `refund`: the linked payment is a refund. Appears on the original charge, pointing to the new refund payout. ```json theme={null} { "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "related_payments": [ { "id": "019e1bab-2ab4-751d-be80-f51c82c2ea64", "relationship": "original", "payment_type": "charge" } ] } ``` Since a refund is created as a payout, the standard `payout.*` webhook events fire for the refund lifecycle. Existing payout handlers track refunds without changes. #### When you can't refund * The charge is not in `paid` status. Use [Resubmit](#resubmit-failed-payments) for failed, reversed, or cancelled charges. * The charge has already been refunded. Each charge can have one refund; check `related_payments` before retrying. * Two requests reach the API at the same time. Straddle uses optimistic concurrency to prevent duplicate refunds: one request succeeds, the other gets a 422 with a clear message. ### Provide proof of authorization When a charge or payout is held for review, or a bank requests evidence against a dispute, you can upload a proof of authorization (POA) document straight to the payment through the API. Upload a document to a charge or payout: * `POST /v1/charges/{id}/authorization` * `POST /v1/payouts/{id}/authorization` Send the file as `multipart/form-data` under the `File` field. A POA document can be a PDF, PNG, JPG/JPEG, DOC, or DOCX, up to 10 MB. Straddle reads the file itself to confirm its type, so renaming a file to end in `.pdf` will not get it past validation. A file that is not one of the accepted types is rejected with a `422`. ```shellscript theme={null} curl -X POST https://api.straddle.com/v1/charges/{id}/authorization \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -F "File=@./proof-of-authorization.pdf" ``` Once a document is uploaded: * The charge or payout object returns it under `documents`, an array whose entries carry `document_id`, `document_name`, `document_type`, `document_size`, and `uploaded_at`. * The `charge` and `payout` webhooks include the same `documents` array, so you can confirm receipt without polling. If you are not integrated with the API, email the POA document to [compliance@straddle.com](mailto:compliance@straddle.com) and the Straddle team attaches it to the payment for you. For what a compliant POA must contain by consent method and SEC code, see the [Proof of Authorization guide](https://help.straddle.com/article/proof-of-authorization-poa-guide) in the help center. ## Important: Same reason, different sources Some reason codes can originate from different sources depending on **when** they're detected: ### `insufficient_funds` | Source | When Detected | Description | | - | - | - | | `watchtower` | Pre-submission | Balance check via Plaid detected insufficient funds **before** network submission | | `bank_decline` | Post-submission | ACH network returned R01/R09 **after** payment was submitted to bank | **Key distinction:** * **Watchtower**: Proactive check using real-time balance data, so the payment never leaves Straddle * **Bank Decline**: Reactive return from the ACH network after the payment was sent ## Status reasons ### Active reason codes These reason codes are actively used by the system: | Reason Code | Description | Sources | | - | - | - | | `ok` | Normal/successful status | `system` | | `insufficient_funds` | Customer's account has insufficient funds | `watchtower`, `bank_decline` | | `closed_bank_account` | Bank account is closed | `bank_decline` | | `invalid_bank_account` | Account cannot be located or is invalid | `bank_decline` | | `invalid_routing` | Invalid ACH routing number | `bank_decline` | | `frozen_bank_account` | Account frozen or OFAC hold | `bank_decline` | | `owner_deceased` | Account owner is deceased | `bank_decline` | | `disputed` | Customer notified bank payment was unauthorized | `customer_dispute` | | `payment_stopped` | Customer placed stop payment order | `watchtower`, `bank_decline` | | `risk_review` | Payment under review by Straddle | `watchtower` | | `payment_blocked` | Blocked by fraud screening | `watchtower` | | `invalid_paykey` | Paykey blocked due to previous failures | `watchtower` | | `amount_too_large` | Exceeds maximum allowed amount | `watchtower` | | `duplicate_entry` | Duplicate transaction detected | `watchtower`, `bank_decline` | | `user_request` | User-requested action | `user_action` | | `other_network_return` | Other network return codes | `bank_decline` | | `payout_refused` | Receiver refused credit | `bank_decline` | ## ACH return codes ### Standard ACH returns (R-codes) | Code | Reason | Message | | - | - | - | | R01 | `insufficient_funds` | The customer's account has insufficient funds | | R09 | `insufficient_funds` | Uncollected funds | | R02 | `closed_bank_account` | The bank account is closed | | R03 | `invalid_bank_account` | The bank account could not be located | | R04 | `invalid_bank_account` | Bank account number invalid (missing digits) | | R13 | `invalid_routing` | Invalid ACH routing number | | R20 | `invalid_bank_account` | Account not eligible for transaction activity | | R05 | `disputed` | Debit to consumer account using corporate consent | | R07 | `disputed` | Authorization revoked by customer | | R10 | `disputed` | Customer advises not authorized | | R11 | `disputed` | Check truncation entry return | | R29 | `disputed` | Corporate customer notified bank unauthorized | | R08 | `payment_stopped` | Customer placed stop payment order | | R14 | `owner_deceased` | Representative payee deceased | | R15 | `owner_deceased` | Beneficiary/account holder deceased | | R16 | `frozen_bank_account` | Account frozen or OFAC hold | | R23 | `payout_refused` | Receiver refused credit | | R24 | `duplicate_entry` | Duplicate entry | | R06+ | `other_network_return` | Various other return reasons | ### Straddle internal codes (S-codes) | Code | Reason | Message | When Applied | | - | - | - | - | | S01 | `payment_blocked` | Invalid routing number | Pre-origination | | S02 | `payment_blocked` | Known bad account number | Pre-origination | | S10 | `payment_blocked` | Invalid account number | Pre-origination | | S11 | `payment_blocked` | Previous R02, R03, R04, R16, or R20 | Pre-origination | | S12 | `payment_blocked` | Previous R05, R07, R08, R10, R11, or R29 | Pre-origination | | S13 | `payment_blocked` | Invalid ODFI credentials | Pre-origination | ## Status details structure Every payment includes detailed status information: ```json theme={null} { "status": "failed", "status_details": { "message": "The customer's account has insufficient funds to cover this payment.", "reason": "insufficient_funds", "source": "bank_decline", "code": "R01", "changed_at": "2024-10-02T14:30:00Z" }, "status_history": [ { "status": "created", "message": "Payment successfully created and awaiting verification.", "reason": "ok", "source": "system", "changed_at": "2024-10-01T10:00:00Z" }, { "status": "scheduled", "message": "Payment successfully validated and scheduled.", "reason": "ok", "source": "system", "changed_at": "2024-10-01T10:05:00Z" }, { "status": "pending", "message": "Payment successfully originated to network.", "reason": "ok", "source": "system", "changed_at": "2024-10-01T14:00:00Z" }, { "status": "failed", "message": "The customer's account has insufficient funds.", "reason": "insufficient_funds", "source": "bank_decline", "code": "R01", "changed_at": "2024-10-02T14:30:00Z" } ] } ``` ## Handling status changes ### Monitoring for status changes ```javascript theme={null} async function handleStatusChange(payment) { const { status, status_details } = payment; switch (status) { case 'created': // Payment created, awaiting verification console.log('Payment created, will be verified soon'); break; case 'scheduled': // Passed verification, queued for processing console.log('Payment verified and scheduled'); // Last chance to cancel if needed break; case 'pending': // CRITICAL: Payment sent to network, cannot stop console.log('⚠️ Payment sent to network - CANNOT BE STOPPED'); await notifyPendingPayment(payment); break; case 'on_hold': // Check source to determine if we can release if (status_details.source === 'user_action') { console.log('User hold - can release when ready'); } else if (status_details.source === 'watchtower') { console.log('Risk hold - cannot release via API'); await notifyCompliance(payment); } break; case 'paid': // Successfully funded console.log('✓ Payment successfully funded'); await fulfillOrder(payment); // Note: Can still reverse later break; case 'failed': // Failed before funding console.log(`✗ Payment failed: ${status_details.reason}`); await handleFailure(payment); break; case 'reversed': // Returned after funding console.log(`⚠️ Payment reversed: ${status_details.reason}`); await handleReversal(payment); break; case 'cancelled': // Terminated before network submission console.log('Payment cancelled'); break; } } ``` ### Handling specific failure reasons ```javascript theme={null} async function handlePaymentFailure(payment) { const { reason, code, source } = payment.status_details; // Determine if retry is possible const retryableReasons = [ 'insufficient_funds', // May succeed later with funds 'duplicate_entry' // Timing issue, may succeed ]; const nonRetryableReasons = [ 'closed_bank_account', 'invalid_bank_account', 'invalid_routing', 'disputed', 'payment_stopped', 'owner_deceased', 'frozen_bank_account', 'invalid_paykey', 'payment_blocked' ]; if (retryableReasons.includes(reason)) { // Can retry after addressing issue await scheduleRetry(payment); } else if (nonRetryableReasons.includes(reason)) { // Cannot retry - need new payment method or investigation await requestNewPaymentMethod(payment.customer_id); } // Log return code for reconciliation if (code) { await logReturnCode(payment.id, code, reason); } } ``` ## Common scenarios ### Successful payment flow 1. `created` → `system` / `ok` - Payment initialized 2. `scheduled` → `system` / `ok` - Verification passed, risk approved 3. `pending` → `system` / `ok` - Sent to ACH network 4. `paid` → `system` / `ok` - Funds successfully transferred ### Pre-submission balance check failure 1. `created` → `system` / `ok` 2. Balance check detects insufficient funds 3. `failed` → `watchtower` / `insufficient_funds` 4. No money moved, payment never sent to bank ### NSF after submission (ACH return) 1. `created` → `scheduled` → `pending` 2. Bank returns with R01 3. `failed` → `bank_decline` / `insufficient_funds` / code: R01 4. No money moved (failed before funding) ### Dispute after funding 1. `created` → `scheduled` → `pending` → `paid` 2. Customer disputes with their bank 3. Bank sends R10 return 4. `reversed` → `customer_dispute` / `disputed` / code: R10 5. Money was moved, then returned ### Risk hold and release 1. `created` → `system` / `ok` - Payment initialized 2. Watchtower flags for review 3. `on_hold` → `watchtower` / `risk_review` 4. Manual review in dashboard 5. If approved: released → `scheduled` → normal flow 6. If declined: → `failed` or `cancelled` ### User-initiated hold 1. `created` → `system` / `ok` 2. User calls hold API 3. `on_hold` → `user_action` / `user_request` 4. User can release when ready 5. Released → continues processing ## Best practices Once pending, payments cannot be stopped. Plan accordingly. The same reason can come from different sources with different implications. Different workflows for pre-funding failures vs post-funding reversals. Log ACH return codes for reconciliation and pattern analysis. ## Next steps Set up real-time status notifications Test various status scenarios in sandbox Learn about charge-specific flows Understand payout-specific scenarios *** # Quickstart guide for the Straddle API Source: https://docs.straddle.com/guides/quickstart Build your first open banking and ACH payment experience with Straddle in minutes. Create a customer, link a bank account, and run your first charge. ## Getting started Welcome! Follow the instructions below to learn how to start building with Straddle. 1. [Sign up for Straddle](https://accounts.straddle.com/sign-up?redirect_url=https%3A%2F%2Fdashboard.straddle.com%2F) 2. Enter your name and email 3. Define your use case: * Select 'Business' if you're building directly into Straddle * Select 'Platform' if your software is enabling payments for other businesses 4. Verify your email and log in to the dashboard Straddle creates an organization that your Account or Platform belongs to. Assign roles to your team members: * Admin * Developer * Member 1. In the dashboard, navigate to the API Keys section 2. Generate a new API key 3. Store your API key securely. You won't be able to view it again Never share your API keys or commit them to version control. Use environment variables to store them securely. 1. In the dashboard, go to the Webhooks section 2. Add a new webhook endpoint URL 3. Select the events you want to receive 4. Save your webhook configuration ## Start building Now that you've set up your account, let's start integrating Straddle into your application. Verify and onboard customers with Straddle Identity. Generate a secure paykey with our Bridge widget or bring your own token. Initiate transactions and move money between accounts. ## Create a customer First, let's create a customer: ```bash theme={null} curl -X POST https://api.straddle.com/v1/customers \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "John Doe", "type": "individual", "email": "john@example.com", "address": { "address1": "123 Main St", "city": "Anytown", "state": "CA", "zip": "12345" }, "phone": "+1234567890", "external_id": "cust_123", "device": { "ip_address": "192.168.1.1" }, "metadata": { "user_id": "12345" } }' ``` All customers are automatically verified by Straddle Identity. The response contains a unique `id` and the `status` of the customer. ```json Verified Customer theme={null} { "meta": { "api_request_id": "b4d5e6f7-g8h9-i0j1-k2l3-m4n5o6p7q8r9" }, "response_type": "object", "data": { "id": "cus_1a2b3c4d5e6f7g8h9i0j1k2l3", "name": "Jane Smith", "type": "individual", "email": "jane.smith@example.com", "phone": "+14155551234", "external_id": "CUST-001", "address": { "address1": "456 Oak Street", "address2": "Apt 7B", "type": "residential", "city": "San Francisco", "state": "CA", "zip": "94102" }, "compliance_profile": { "dob": "1985-03-15", "ssn": "***-**-1234" }, "device": { "ip_address": "192.168.1.1" }, "metadata": { "referral_source": "website", "customer_segment": "premium" }, "status": "verified", "created_at": "2023-11-08T15:30:45Z", "updated_at": "2023-11-08T15:30:45Z" } } ``` After creating a customer, you can optionally review the underlying score data. This is useful if you want to understand the risk of the customer or if they are flagged for manual review.

Learn more about the Review Endpoint \[\[future link]]
## Use Bridge to generate a Paykey Straddle uses a new kind of payment token called a `paykey` to securely link bank accounts to customers. Straddle generates paykeys using its proprietary machine learning model, WALDO. WALDO algorithmically matches customer profile data to account ownership details sourced directly from the bank. You can generate a paykey in two ways: 1. Using a Plaid token from an existing integration 2. With 'raw' bank account details ```bash Use a Plaid Token theme={null} curl -X POST https://api.straddle.com/v1/bridge/plaid \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "{customer_id}", "plaid_token": "PLAID_PROCESSOR_TOKEN", "metadata": { "user_id": "12345" } }' ``` ```bash Use a Bank Account theme={null} curl -X POST https://api.straddle.com/v1/bridge/bank_account \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "{customer_id}", "routing_number": "110000000", "account_number": "000123456789", "account_type": "checking", "metadata": { "user_id": "12345" } }' ``` Replace `{customer_id}` with the actual customer ID and fill in the appropriate fields depending on the type of paykey you're generating. The API response contains the paykey: ```json Paykey Response theme={null} { "meta": { "api_request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a" }, "response_type": "paykey", "data": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "label": "John's Checking Account", "source": "bank_account", "institution_name": "Bank of America", "status": "active", "status_details": { "message": "Account successfully verified", "reason": "OK", "source": "system" }, "expires_at": "2023-11-07T05:31:56Z", "created_at": "2023-11-07T05:31:56Z", "updated_at": "2023-11-07T05:31:56Z", "paykey": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D", "bank_data": { "routing_number": "123456789", "account_number": "****5678", "account_type": "checking" }, "metadata": { "user_id": "user_9876543210" } } } ``` In this example, the value of the `paykey` is `vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D`. ## Create a payment Now that you have a paykey, you can send money to customers via payouts or collect money from them via charges: ```bash Create a Charge theme={null} curl -X POST https://api.straddle.com/v1/charges \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paykey": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D", "description": "Test charge", "amount": 1000, "currency": "usd", "payment_date": "2023-06-01", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "charge_123", "config": { "balance_check": "required" }, "metadata": { "order_id": "12345" } }' ``` ```bash Create a Payout theme={null} curl -X POST https://api.straddle.com/v1/payouts \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "paykey": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D", "description": "Test payout", "amount": 1000, "currency": "usd", "payment_date": "2023-06-01", "device": { "ip_address": "192.168.1.1" }, "external_id": "payout_123", "metadata": { "refund_id": "12345" } }' ``` # Securely share data with Straddle Source: https://docs.straddle.com/guides/resources/datashare Upload encrypted customer or transaction data for proofs of concept and portfolio scrubs using Straddle SFTP and PGP encryption procedures. Straddle may request your organization to upload files for additional analysis or for a proof of concept of various services. Payment and sensitive personal data must **always** be encrypted before it can be shared with Straddle. Examples of files that can be uploaded include: * **Feedback files**: Consumer, business, or bank account records that **have** been scored by Straddle. * **POC (Proof of Concept) files** and **Retro files**: Records that **have not** been scored by Straddle. All files must be in CSV format and encrypted using the [Gnu Privacy Guard (GPG)](https://gnupg.org/) implementation of the Pretty Good Privacy (PGP) encryption standard before they are uploaded to the Straddle file server. ## **How it works** Compile your data with the required and requested data field types. Save the file in CSV format with the correct naming convention. For more information on the required data field types, see the [data field types](https://docs.google.com/spreadsheets/d/1WkwpdEpLAC8SfxaP88iQI_9fAZ4sDyrhR0VEq6I49Lw/edit?usp=sharing) document. Every data file sent to Straddle must be encrypted using the Straddle-provided PGP public key. Do not use any other public keys for encryption. Straddle provisions you with a public PGP key pair for encryption. You can access the PGP public key below. Once you have encrypted the CSV file with the PGP public key, you can upload the file to the Straddle file server. ## **Create a CSV file** Compile your data with the required and requested data field types. Save the file in CSV format with the correct naming convention. For more information on the CSV file requirements for different file types, see the following: * For Feedback files, see Send Feedback Data via CSV File. * For POC and Retro files, contact your Account Manager or review the sample below. The maximum size per file allowed to send is 4 GB. * [File definitions and sample](https://docs.google.com/spreadsheets/d/1WkwpdEpLAC8SfxaP88iQI_9fAZ4sDyrhR0VEq6I49Lw/edit?usp=sharing) ## **Download the Straddle PGP public key** Every data file sent to Straddle must be encrypted using the Straddle-provided PGP public key. Do not use any other public keys for encryption. Straddle provisions you with a public PGP key pair for encryption. You can access the PGP public key in one of the following ways: ### **Download file** Download the Straddle PGP public key from openpgp.org ### **Manual import** | | | | :- | :- | | KeyID | 74D819E55C5370643190B149F40DA06AFEFE8A33 | | Key type | RSA | | Key size | 4096 | | Fingerprint | 74D8 19E5 5C53 7064 3190 B149 F40D A06A FEFE 8A33 | | User ID | straddle share \<[trust@straddle.com](mailto:trust@straddle.com)> | ```PGP Key [expandable] theme={null} -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: 74D8 19E5 5C53 7064 3190 B149 F40D A06A FEFE 8A33 Comment: straddle share xsFNBGfuwE0BEADci8/bTkp0isHIv089/YG7feh/CnVvpIE0xuSbDphjrHwlSTWV VhgW+yMBVqB6VniNEW142CQyyMQp9UI5fUJ9CyUnq/e76F3AeOYHHjr/w/A232Vb BlU3j++fYzu7W2cmV8HRWohWOsd0juTNrLULWJenMMZ7/lR0FHfzqoymnyNEZN8m 8hDk8cb+jEvZ2X59adFtDzE4Ho/jd3oEEkHNbWXxpLWLCF4SBmgOcCaVDY+3GM52 F4nZT0GfJhVRVIduAU8rx9LmlKNY+JA9V5VfLM3JVgQNlg5B5NNuSy2JZ+ljpLon Oy401EVsiTRLOlQPb0oWqS1WisUowLN77GZE0I+PVFe30LcnJSkrUjBS7nGrR/52 TKmq8j8EzpbN615zx2Eypi428Pw4BrgYExgv2d2PmXiqyBCx1SYrmajoKs80qJtP rgQbiuC7rhkj/iA0Mz+6tHoZJI6BQL+ewNyqJOIRaoXp3rehJYunHJWvn3UGeIDS IvCPx+Yc5GGEiSAwi2D1ERO6UjZdspdRL7FzJB5+LfBicrNcoJim7vQi4lg8716v jEYd5HrluuDXr/el9fKMvPyRPEQb4nEz6pGZ0Kpkxc6WxPAWFDuy2YKjpmuoA7X2 gRXhRF8fs4Le7OHPB9C1xmfJbssQ0W8YPPSbCHpLFADX3Da71Mpbk9qHywARAQAB zSJzdHJhZGRsZSBzaGFyZSA8dHJ1c3RAc3RyYWRkbGUuaW8+wsGUBBMBCAA+FiEE dNgZ5VxTcGQxkLFJ9A2gav7+ijMFAmfuwE0CGwMFCQeGHv8FCwkIBwIGFQoJCAsC BBYCAwECHgECF4AACgkQ9A2gav7+ijM0AxAAst2NPFc1sQubBCBifYf6tr0zgrjP u5FIEcrxOIDD7U9fZXG1CIzSnu9RN7C9FOqI9CypDvWKmpnuyHR8yS6PXk9QSmOt srzj+s2/DogDIUdYWMtIa4PH+Mek5eQyyCxXikiGgBYqsXCHMr11+RDEmiREaHjY /SxP3O62tMD2bVjseeX9EOmihFfd+ShZ6oJKsW7qpzUAis4UGai8RVJ9Tu8ir4yR 3DdBeUVC+qADYXeKPYVxiNK25hIFl9/QBW5Biy4A+95Ese0YT7TTGFwL3V1PySkz ScXYxH7qg+/PKjWaP8vH6BiQqJoha+/i3zkXoDzMx01Nlt8ly3IODlQj8EDSZmqo Z4tRR4j7oI5wT/su1NY1dQ98EaU+84kndVqMMjEfQMZJeDNK1ftQeAEih8TLUse2 r6QZN2bHjNhIRy/XB8Fgw7ovvs2INsm5Ie9Vlv2LVTfGp95bJ4oPQe42oUH8mHPV YEmZ7cZ+s88nhFkbn2yhkZIUw5ueLDryvyIzoNIDNHtWccnIWfDjVnzQsotxISBg +ncDJfGHmSsulMCbYGUUBfvolwGXrR6MdtxUjtiGRBe4m75G06CyfvbplEkjzvuS QVh6ngoc1DDbTauF13IWM532s/eDpKeEcRvnH8+bL4YIrGNh2ldXLUDf+T3+sgIc JzMCp5S2oSG3eOPOwU0EZ+7ATQEQAKq4mRz3+HzM0x1jPYThZIro107ohpg4WKU8 X+4wr1iH7IcC0ApuaKZ1fetU+xlsK0gDfLHH/F0KP3WWbjPOzpgVkPBybzoUNb4x 2z5gVoTdC6iMEhpimKSdZqG2DjyTpjZ55e6uI7Bd3/2BYQE3DYqH3bGtf3hJvK8B Q3zzIPz3yHCE7YEU0Wje10qjbQojTZHsxaK6g9n8l2UC5hS4GzRmmno9/7ZWk9AO +26vMMQPRFnZzYsDAGaixFYddC7YF2KRWc8ecLzB3OJWZRjmEGvG0DEW7qAAyW1I tV9kYH4/sqPIS/9+pYh3ARLZ0P74EjL6ZPOVMWznRcFSyzOPQOFOr11B5D1oEXKn +XxjGtW6VpIK5Y0UeX69bGVDarAOz7ZcDrk8P0AioDOAsxf7iEavzE9SPAROmgD0 GK9T+/GZAfvldq0ITrA3affp2HmpbjQnJkBQFEDORbQW1l7e+1+pK5k/39y3e689 YVE/+2MpSmG9f81+1e2cEpZqyNFNjZrfEYhkgIk6DH9Ejt3GAYydnv0TtgOpf91P fhXEKJoAi7hKa5YYxelAh+cRFVKPEyO2zTrVtWu+HzCo6J3XApkSuhUWExCCZQtb qjmYccdRflRrFBiz0PyFqAcc4Vw3BpU4tE2akIoyPM4ohA5AMfYUVPGktPvCCjrD yfOIAI33ABEBAAHCwXwEGAEIACYWIQR02BnlXFNwZDGQsUn0DaBq/v6KMwUCZ+7A TQIbDAUJB4Ye/wAKCRD0DaBq/v6KM0+DEACuUQoGpkYwqKIsDhmhL6tmzlSt4sTB Ea4JYSrNpATYZbta+NTIA6NaCojKYGO24vd1QfywToMnA8jofxhVYZ3+rrqRKMAj sfpCNPEN+7JuE2DthQS9mfUiu7BCtlPRlXUf4v0ltRFpCVVXekvDKlAZ/axXO+Iu aGm0V27Cu/on53UMJ33MBfq6mUnvdgmpFLmbvbfm/v6wyoJaMaL62UYdqOfHeDDX a2U2aM8fM4YjOdITrwAeSIOyDgMokxC5Haq2MF4n27ynwriHhuPLluVtZ0UxMkjJ e/5KAwLpluwpRtlvviHmj2cXhQnXhVj4y+29Q1vljIiW+MA8zCky7p7qSlHgc5FZ 6cVLwXNQCCG4d6PREAVVO1NtHJtyU0wAKvdfRk9F+r7dpUANEHs6XGJw6vKtLjTd EjPQ5/X9xYI6ygDUcnwIHV72CJP+WIBfkWHfVKBElqPQrkw4f4uru0RM4bWAWBpM 4V7GNJqYDqAoYxe3kf2w1r0LyWP3KFEvF1CyZ1pjAK7PHvzEKDnYpeIiWlTd3pB7 hVJpj3syzkymly1uA+dwbm8IunDhrep8mJZJT9tOJpW6kcfOZqRany3CSN63VACq yyV5KNgIGr1ANBoq0sLnqf3tj164bx5xCWkFbE57/bK9B3g9Y5RBI5TdERyuHE8s BXuD9U5u+XwFVA== =4VAn -----END PGP PUBLIC KEY BLOCK----- ``` ### ## **Encrypt the CSV file with PGP** Do not sign the file before or after encryption. The file encryption process in this section uses the [Gnu Privacy Guard (GPG)](https://gnupg.org/) implementation of the PGP encryption standard. To encrypt your CSV file, complete the following steps: 1. Open the command line on your computer. 2. Import your Straddle PGP key with the following command: ``` gpg --import {key}.asc ``` 3. If successful, the command line returns a message similar to the following: ``` gpg: key 6CFE17E37C6960B7: public key "straddle share " imported gpg: Total number processed: 1 gpg: imported: 1 ``` 4. Use the --encrypt option to encrypt the file and specify the following options: * * clientname\_encrypted.gpg: The name of the newly encrypted file. * [trust@straddle.com](mailto:trust@straddle.com): The name of the encrypted file recipient. * filename.csv: The name and path of the CSV file. * The following is an example of the encryption command with all options specified: ``` gpg --output clientname_encrypted.gpg --encrypt --recipient trust@straddle.com filename.csv ``` ## **Send encrypted files using secure upload** 5. Once the file is encrypted, you can send it securely using the [Straddle DataShare](https://strddl.co/datashare) service. # Sandbox simulation testing for Pay by Bank Source: https://docs.straddle.com/guides/resources/sandbox-paybybank Test charge, payout, and return scenarios with deterministic outcomes in the Straddle Pay by Bank sandbox using simulation amounts and test paykeys. Testing payment workflows in a sandbox environment traditionally requires navigating complex setup processes and waiting for simulated payment network processing delays. Our sandbox simulation feature transforms this experience by allowing you to define specific outcomes for your test scenarios, making integration testing both faster and more reliable. This guide walks you through using sandbox simulations to test various payment scenarios efficiently. You'll learn how to simulate successful payments, fraud detection, insufficient funds, and other real-world scenarios without complex manual setup or extended wait times. ## Understanding sandbox simulations In production environments, payment processing involves asynchronous workflows, network processing windows, and various unpredictable outcomes. While our sandbox maintains this asynchronous behavior to ensure realistic testing, we've introduced a powerful simulation feature that gives you control over test transaction outcomes. The core of this system is the `config` object with its `sandbox_outcome` field. Think of this as your way to instruct the sandbox exactly how a test transaction should behave, while still maintaining the proper asynchronous flow that mirrors production behavior. Sandbox simulations maintain asynchronous processing to match production behavior. While outcomes are deterministic, they still follow realistic timing patterns to ensure your integration handles asynchronous workflows correctly. ## How simulations work When you create an entity (`customer`, `paykey`, `charge`, or `payout`) in the sandbox, you can include a `config` object that specifies your desired outcome: ```json theme={null} { "config": { "sandbox_outcome": "paid" } } ``` This configuration tells the sandbox to simulate a specific scenario. For example, setting `"sandbox_outcome": "paid"` on a charge causes it to: 1. Process normally through the initial states 2. Transition to `scheduled` ->`pending` status 3. Automatically move to `paid` status within a few minutes In the sandbox environment, simulated payments process every minute rather than waiting for standard network windows. This accelerates your testing cycle while maintaining realistic state transitions. ## Available simulation outcomes Understanding the available simulation options helps you create comprehensive test scenarios that cover all possible production behaviors. Let's explore what you can simulate for each entity type. Control customer verification status during creation: | Outcome | Description | Use Case | | - | - | - | | `standard` | Customer undergoes normal review process | Testing standard onboarding flow | | `verified` | Customer automatically becomes verified | Testing post-verification features | | `rejected` | Customer automatically gets rejected | Testing rejection handling | | `review` | Customer enters manual review status | Testing review queue workflows | Define paykey authorization states: | Outcome | Description | Use Case | | - | - | - | | `standard` | Paykey follows normal review process | Testing standard authorization | | `active` | Paykey becomes immediately active | Testing active payment methods | | `rejected` | Paykey gets rejected | Testing rejection scenarios | | `review` | Paykey requires manual review | Test scenarios requiring human or automated intervention | Simulate various payment outcomes: **Success Scenarios** | Outcome | Description | Timing | | - | - | - | | `standard` | Normal processing | Follows standard windows | | `paid` | Successful payment | Transitions to paid within minutes | **Hold and Cancellation Scenarios** | Outcome | Description | Next Steps | | - | - | - | | `on_hold_daily_limit` | Held due to daily limits | Can be manually released | | `cancelled_for_fraud_risk` | Cancelled for fraud detection | Terminal state | | `cancelled_for_balance_check` | Cancelled due to balance check | Terminal state (charges only) | **Failure Scenarios** | Outcome | Description | Error Code | | - | - | - | | `failed_insufficient_funds` | Fails due to NSF | R01 | | `failed_customer_dispute` | Fails due to dispute | R05 | | `failed_closed_bank_account` | Fails due to closed account | R02 | **Reversal Scenarios** | Outcome | Description | Error Code | | - | - | - | | `reversed_insufficient_funds` | Paid then reversed for NSF | R01 | | `reversed_customer_dispute` | Paid then reversed for dispute | R05 | | `reversed_closed_bank_account` | Paid then reversed for closed account | R02 | Reversal scenarios are particularly valuable for testing reconciliation logic, as they simulate payments that initially succeed but are later reversed, a common real-world scenario that can be challenging to handle correctly. ## Practical examples Let's walk through complete testing scenarios, starting from creating test entities to processing payments. These examples demonstrate how to build realistic test cases from start to finish. ### Prerequisites Before testing payment flows, ensure you have: * Created a sandbox organization and account * Obtained your sandbox API credentials * Set up [webhook](/webhooks/overview/events) endpoints for receiving notifications ### Example 1: Testing successful payment flow This example demonstrates the complete happy path for payment processing. First, create a customer that's pre-verified to skip the review process: ```bash theme={null} curl --request POST \ --header 'Authorization: Bearer YOUR_SECRET_API_KEY' \ --url https://sandbox.straddle.com/v1/customers \ --header 'Content-Type: application/json' \ --data '{ "name": "Ron Swanson", "type": "individual", "email": "user@example.com", "phone": "+12128675309", "device": { "ip_address": "192.168.1.1" }, "config": { "sandbox_outcome": "verified" } }' ``` Save the `customer_id` from the response. You'll need it for the next steps. Create a payment method that's immediately active: ```bash theme={null} curl https://sandbox.straddle.com/v1/bridge/bank_account \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --header 'Straddle-Account-Id: YOUR_ACCOUNT_ID' \ --data '{ "customer_id": "YOUR_CUSTOMER_ID", "account_number": "123456789", "routing_number": "021000021", "account_type": "checking", "config": { "sandbox_outcome": "active" } }' ``` The response includes a `paykey` that you'll use to create charges. Now create a charge that will automatically succeed: ```bash theme={null} curl https://sandbox.straddle.com/v1/charges \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "paykey": "", "description": "Monthly subscription fee", "amount": "10000", "currency": "", "payment_date": "2019-12-27", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "", "config": { "balance_check": "enabled", "sandbox_outcome": "paid" } }' ``` This charge will: * Create with status `created` * Move to `pending` as it enters processing * Transition to `paid` within a few minutes Your webhook endpoint should receive these status events: 1. `created` - Initial charge creation 2. `scheduled` - Transaction verified and queued for origination 3. `pending` - Charge delivered to network 4. `paid` - Funding complete ### Example 2: Testing fraud detection This scenario helps you verify your system properly handles fraud prevention measures. Use a new `customer` and `paykey` creation process from Example 1, or reuse existing test entities. ```bash theme={null} curl https://sandbox.straddle.com/v1/charges \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "paykey": "", "description": "Monthly subscription fee", "amount": "10000", "currency": "USD", "payment_date": "2025-05-27", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "ABCD-4567", "config": { "balance_check": "enabled", "sandbox_outcome": "cancelled_for_fraud_risk" } }' ``` The charge is immediately cancelled. Your system should: * Receive a `cancelled` webhook status * Display appropriate messaging to users * Log the fraud detection for analysis ### Example 3: Testing payment reversals Reversals represent a particularly challenging scenario since the payment initially succeeds. This example shows how to test your reversal handling logic. For this test, let's create a customer that requires review: ```bash theme={null} curl --request POST \ --header 'Authorization: Bearer YOUR_SECRET_API_KEY' \ --url https://sandbox.straddle.com/v1/customers \ --header 'Content-Type: application/json' \ --data '{ "name": "Ron Swanson", "type": "individual", "email": "user2@example.com", "phone": "+12128675308", "device": { "ip_address": "192.168.1.1" }, "config": { "sandbox_outcome": "verified" } }' ``` ```bash theme={null} curl https://sandbox.straddle.com/v1/paykeys \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --header 'Straddle-Account-Id: YOUR_ACCOUNT_ID' \ --data '{ "customer_id": "YOUR_CUSTOMER_ID", "type": "bank_account", "bank_account": { "account_number": "987654321", "routing_number": "021000021", "account_type": "checking" }, "config": { "sandbox_outcome": "active" } }' ``` ```bash theme={null} curl https://sandbox.straddle.com/v1/charges \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "paykey": "", "description": "Monthly subscription fee", "amount": "10000", "currency": "USD", "payment_date": "2025-05-27", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "ABCD-1234", "config": { "balance_check": "enabled", "sandbox_outcome": "reversed_insufficient_funds" } }' ``` This creates a realistic reversal scenario where: 1. The charge processes normally 2. Transitions to `paid` status 3. Your webhook receives a success notification 4. Minutes later, the charge reverses to `reversed` status 5. Your webhook receives a reversal notification with code R01 Your system should handle both the initial success and subsequent reversal appropriately. ### Example 4: Testing daily limit holds This scenario tests your ability to handle and release held payments. ```bash theme={null} # Create a charge that exceeds daily limits curl https://sandbox.straddle.com/v1/charges \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "paykey": "", "description": "Monthly subscription fee", "amount": "10000", "currency": "USD", "payment_date": "2025-05-27", "consent_type": "internet", "device": { "ip_address": "192.168.1.1" }, "external_id": "ABCD-123456789", "config": { "balance_check": "enabled", "sandbox_outcome": "on_hold_daily_limit" } }' ``` The charge is created with `on_hold` status. You can then test releasing the hold through your admin interface or API endpoints. ## Production behavior Understanding how sandbox simulations behave in production is crucial for safe deployment. The system is designed with multiple safeguards to prevent any simulation logic from affecting production operations. In production environments: * The `sandbox_outcome` field is nullable at the API level * If included, it must be set to `"standard"` to pass validation * The field is excluded from all API responses * No simulation logic runs in production systems This design ensures that: * Test code accidentally deployed to production won't cause unexpected behavior * Production API responses remain clean and consistent * There's no performance impact from simulation logic * Your production integration remains secure and predictable ## Best practices To maximize the value of sandbox simulations, consider these comprehensive testing strategies. ### Create comprehensive test suites Build test suites that cover every possible outcome your integration might encounter: ```javascript theme={null} // Example comprehensive test suite structure const testScenarios = [ // Success scenarios { name: "Standard processing", outcome: "standard" }, { name: "Successful payment", outcome: "paid" }, // Failure scenarios { name: "Insufficient funds", outcome: "failed_insufficient_funds" }, { name: "Customer dispute", outcome: "failed_customer_dispute" }, { name: "Closed account", outcome: "failed_closed_bank_account" }, // Reversal scenarios { name: "NSF reversal", outcome: "reversed_insufficient_funds" }, { name: "Dispute reversal", outcome: "reversed_customer_dispute" }, // Hold and cancellation scenarios { name: "Daily limit hold", outcome: "on_hold_daily_limit" }, { name: "Fraud detection", outcome: "cancelled_for_fraud_risk" }, { name: "Balance check failure", outcome: "cancelled_for_balance_check" } ]; // Run each scenario and verify your system handles it correctly for (const scenario of testScenarios) { await testPaymentScenario(scenario); await verifySystemState(scenario.expectedState); await verifyWebhookHandling(scenario.expectedEvents); } ``` ### Document test data Maintain clear documentation of your test scenarios and their purposes: ```javascript theme={null} // Good practice: Self-documenting test data const createTestCharge = async (scenario) => { const charge = await straddle.charges.create({ amount: scenario.amount || 5000, currency: "usd", customer_id: scenario.customerId, paykey: scenario.paykey, description: `Test: ${scenario.description}`, metadata: { test_scenario: scenario.name, expected_outcome: scenario.outcome, test_run_id: generateTestRunId(), tested_at: new Date().toISOString() }, config: { sandbox_outcome: scenario.outcome } }); // Log test execution for debugging console.log(`Created test charge ${charge.id} for scenario: ${scenario.name}`); return charge; }; ``` ## Troubleshooting When simulations don't behave as expected, check these common issues and their solutions. **Symptoms:** * Entity doesn't follow the specified outcome * Unexpected status transitions * Missing webhook events **Solutions:** 1. Verify you're using the sandbox environment URL: `https://sandbox.straddle.com` 2. Check that the outcome value is spelled exactly as documented 3. Ensure the `config` object is properly formatted in your JSON request 4. Confirm your API credentials have the necessary permissions **Symptoms:** * Transitions happen too quickly or slowly * Unexpected delays between states * Webhooks arrive out of order **Solutions:** 1. Remember sandbox processes payments every minute (not real ACH timing) 2. Network latency can affect webhook delivery order 3. Use webhook event timestamps, not arrival time, for sequencing 4. Implement idempotency to handle duplicate webhook deliveries **Symptoms:** * Expected webhooks don't arrive * Receiving duplicate webhook events * Webhook signature validation fails **Solutions:** 1. Verify your webhook endpoint returns 200 status quickly 2. Check webhook endpoint configuration in your account settings 3. Ensure your endpoint can handle concurrent requests 4. Implement proper webhook signature validation 5. Log all received webhooks for debugging **Symptoms:** * Concerns about sandbox config in production * Validation errors in production * Unexpected behavior after deployment **Solutions:** 1. The field is safely ignored in production 2. Use environment variables to conditionally include config 3. Set up separate test and production code paths 4. Add production deployment checks to catch test code While sandbox simulations make testing significantly easier, always perform end-to-end testing with standard processing before deploying to production. This ensures your integration handles the full complexity of real-world payment processing, including edge cases and timing variations that simulations might not capture. # Platform sandbox quickstart Source: https://docs.straddle.com/guides/resources/sandbox-platform Quickly create and onboard test embedded accounts in the Straddle sandbox to validate your platform integration before going live with production accounts. Before testing Pay by Bank flows that require the `Straddle-Account-Id` header, you'll need to create an organization and at least one related account. In the sandbox environment, this process is streamlined - you can create accounts instantly without completing onboarding or requesting capabilities. If this doesn't quite make sense yet, check out our [Embedded Account](/guides/embed/api-headers) guide before proceeding. ## Setup process We provide a Postman collection and sample data to help you get started quickly. Select the button below to import our collection or read along for direct links to the relevant API endpoints. The sample data below is fully functional and can be used exactly as shown. Just save both the `organization_id` and `account_id` from the responses - you'll need them for future API calls in the sandbox environment. ### Step 1: Create an organization First, create an organization that will contain your test accounts. You can use either: * Our [Create Organization](https://www.postman.com/strddl/straddle/request/ch9zo0v/create-an-organization?action=share\&creator=30656205\&ctx=documentation\&active-environment=30656205-5d917c7f-9c3c-49dd-ba7b-e66047f4b29d) Postman request, or * Direct API call using this ready-to-use sample data (you can copy and paste this exactly as-is): ```bash theme={null} curl https://sandbox.straddle.com/v1/organizations \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --data '{ "name": "Prestige Worldwide", "metadata": { "industry": "Shipping", "size": "Enterprise", "headquarters": "San Francisco" }, "external_id": "org_12345" }' ``` The API returns an `organization_id` (a UUID) that you'll need for the next step. Organizations allow you to manage multiple related business accounts under a single umbrella. Each account represents a business that will use Straddle's services. For sandbox testing, one organization is likely all you need, but you do you. ### Step 2: Create a test account Create a business account within your organization using either: * Our [Create Account](https://www.postman.com/strddl/straddle/request/rol2jyy/create-an-account?action=share\&creator=30656205\&ctx=documentation\&active-environment=30656205-5d917c7f-9c3c-49dd-ba7b-e66047f4b29d) Postman request, or * Direct API call using this complete sample payload (just replace `{uuid}` with the `organization_id` from step 1): ```json theme={null} { "organization_id": "{uuid}", "account_type": "business", "business_profile": { "name": "Prestige Worldwide", "website": "https://strddl.co", "legal_name": "Prestige Worldwide LLC INC LTD", "description": "Leading provider of cruise entertainment", "use_case": "Collecting fees for boat trips", "tax_id": "12-3456789", "phone": "+15555555555", "address": { "line1": "123 Innovation Drive", "line2": "Suite 200", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US" }, "industry": { "mcc": "4457", "sector": "Transportation and Facilities", "category": "Boat Rentals and Leases" }, "support_channels": { "email": "support@donotemail.com", "phone": "+15559876543", "url": "https://strddl.co/support" } }, "access_level": "standard", "metadata": { "contract_renewal": "october", "account_manager": "bob@yourcompany.com" }, "external_id": "biz_12345" } ``` In the sandbox environment: * Accounts are created instantly * All capabilities are automatically enabled * No verification or onboarding is required * You can start testing payment flows immediately ## Using your test account Once you receive the `account_id` in the response, include it in the `Straddle-Account-Id` header for subsequent API calls: ```bash theme={null} curl --request POST \ --url https://sandbox.straddle.com/v1/charges \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \ --header 'Straddle-Account-Id: YOUR_ACCOUNT_ID' \ --header 'Content-Type: application/json' ``` ## Next steps With your sandbox organization and account created, you can immediately begin: * Testing payment flows * Creating webhooks * Simulating different scenarios Remember that sandbox credentials and accounts cannot be used in production. When you're ready to go live, you'll need to create production organizations and accounts, which will require full onboarding and verification. # Synthetic identity fraud explained Source: https://docs.straddle.com/guides/resources/synthetic-identity Learn what synthetic identity fraud is, how it impacts ACH and bank payments, and how Straddle's identity verification platform detects and prevents it. # Understanding Synthetic Identity Fraud In today's digital economy, businesses face an increasing threat from sophisticated fraudsters. One of the fastest-growing forms of identity theft is synthetic identity fraud. This guide helps you understand what synthetic identity fraud is, how it differs from traditional identity theft, and strategies to protect your platform. ## What is synthetic identity fraud? Synthetic identity fraud occurs when genuine information is combined with fabricated information to create a new, false identity. Synthetic identities may appear credible, allowing fraudsters to: * Open new accounts * Make fraudulent purchases * Exploit financial systems A 2023 report from Thomson Reuters estimated losses due to synthetic identity in the range of [“\$20 to 40 billion and growing”](https://www.moodys.com/web/en/us/kyc/resources/insights/synthetic-identities-and-why-they-are-important-in-todays-digital-landscape.html#:~:text=Synthetic%20IDs%20can%20be%20leveraged,to%2040%20billion%20and%20growing.%E2%80%9D). ## Types of synthetic identities Fraudsters typically create synthetic identities in two ways: A genuine identity with one or more personal details altered. For example, a consumer with low credit might manipulate their identity to hide their previous history. A combination of real and false information to create an entirely new identity. This identity does not belong to any known or real person. ## Synthetic vs. traditional identity theft | Aspect | Synthetic Identity Fraud | Traditional Identity Theft | | - | - | - | | **Identity Creation** | Creates a new, false identity | Steals an existing, real identity | | **Detection Time** | May go undetected for longer periods | Often reported quickly by the victim | | **Victim Reporting** | No direct individual victim to report fraud | Individual victim can alert authorities | | **Impact** | Affects financial systems and businesses | Directly impacts the individual whose identity was stolen | | **Detection Difficulty** | More challenging due to lack of victim reports | Easier due to victim complaints and unusual activity | ## How fraudsters use synthetic identities Synthetic identities are often used in: 1. **Financial Services**: * Opening new accounts * Building credit history over time * Obtaining larger credit lines 2. **Ecommerce and Online Marketplaces**: * Creating accounts with lower verification requirements * Making high-value purchases * Obtaining chargebacks, increasing merchant losses Fraudsters may cultivate synthetic identities for months or even years before using them for fraudulent activities, making detection challenging. ## Protecting your platform To combat synthetic identity fraud effectively: 1. Implement robust identity verification processes 2. Use advanced fraud detection technologies 3. Monitor account behavior over time 4. Educate your team about the latest fraud trends 5. Collaborate with other businesses and law enforcement Straddle's identity verification and fraud detection capabilities can help protect your platform from synthetic identity fraud. Our API integrates seamlessly into your onboarding and transaction processes to identify potential risks. By understanding synthetic identity fraud and implementing strong protective measures, you can safeguard your business and customers from this growing threat. # WALDO: Identity Matching Source: https://docs.straddle.com/guides/resources/waldo WALDO is Straddle's proprietary identity matching algorithm that verifies a customer's identity matches the ownership details of their linked bank account. Built on LSTM-based natural language processing algorithms and deployed through a cloud-native architecture, Waldo provides a robust API delivering high-accuracy name matching with exceptional performance. By accounting for cultural, typographical, and formatting differences, Waldo helps organizations improve data quality, streamline operations, and enhance the customer experience. **WARNING: NERDS ONLY** ## Overview WALDO stands for **W**eighted **A**lgorithm for **L**egitimate **D**ata **O**wnership. It is Straddle's proprietary identity matching algorithm designed to securely and accurately verify that a customer's identity matches the ownership details of their bank account. Determining if two name strings refer to the same individual is deceptively complex. Traditional string comparison methods often fail to capture the multidimensional nature of name representation, resulting in high rates of false positives or false negatives. Name variations arise in many ways. Common names frequently have multiple accepted spellings, such as “Jonathan” vs. “Johnathan,” and informal nicknames (e.g., “Elizabeth” vs. “Liz,” “Beth,” or “Betty”) complicate matching further. Cross-cultural factors introduce additional layers, as names transliterated from languages with different alphabets can appear under multiple spellings (e.g., the Russian “Михаил” might be “Mikhail,” “Michael,” or “Mihail”). Variations in name ordering, suffixes (“Jr.,” “Sr.,” “III”), and honorifics (“Dr.,” “Prof.”) also add complexity. Finally, typographical errors and data-entry mistakes create further inconsistencies. This multidimensional challenge leads to significant business costs when simplistic approaches produce poor results. Waldo is designed to address these complexities, facilitating more accurate name recognition and reducing operational risk. ## The need for advanced identity to ownership matching Variations in name spellings, typos, nicknames, and cultural naming conventions can lead to mismatches. Malicious actors may attempt to connect bank accounts they do not own. Financial regulations require stringent identity verification processes to prevent money laundering and other illicit activities. Traditional identity verification methods can be intrusive and negatively impact conversion rates. ### Importance of accurate identity matching * **Security**: Ensures that only authorized individuals can initiate transactions. * **Trust**: Builds confidence among users that their financial information is protected. * **Compliance**: Satisfies legal obligations for identity verification and fraud prevention. * **Efficiency**: Reduces false positives and the need for manual reviews. ## How WALDO works ### **Name normalization** Waldo first normalizes input names by: 1. Converting characters to a common case and trimming extraneous whitespace. 2. Identifying and separating suffixes (e.g., “Jr,” “Sr,” “II”) from the main name components. 3. Standardizing punctuation (e.g., handling “O’Brien,” “O Brien,” “OBrien,” “O-Brien” consistently). This step removes superficial formatting discrepancies, reducing false negatives that arise from differences in casing, punctuation, or whitespace. ### **Name variation generation** Waldo generates multiple plausible variations for each name, reflecting common changes seen in real-world data: * **Reordering**: First name–last name, inversions, and optional middle names. * **Nicknames**: Associating formal names with known diminutives (e.g., “Robert” → “Rob,” “Bob,” etc.). * **Initials**: Handling records that use initials instead of full names. By comparing an expanded set of variations for each input, Waldo finds matches that simpler approaches would overlook, reducing false negatives. ### **Similarity calculation** 1. **Pairwise Comparisons**: For each variation of `name1` and `name2`, Waldo applies specialized string, cultural, and phonetic comparisons from the HMNI library. 2. **Maximum Similarity Extraction**: The system takes the highest similarity score across all variation pairs, representing the closest possible match. 3. **Business Rules**: Additional refinements incorporate domain logic—for example, distinguishing family name matches vs. first-name inconsistencies. 4. **Score Normalization**: The final score is normalized to a 0–100 range, enabling straightforward thresholding and integration into client workflows. This multistage process yields substantially higher accuracy than simple string comparison methods, crucial for real-world data sets prone to typographical errors and diverse naming conventions. ## Integration with Pay by Bank * Data Collection: The customer provides personal information during onboarding. * Real-Time Verification: Straddle ID verifies the customer's identity using various data sources and compliance checks (KYC, AML). * Identity Profile Creation: A verified identity profile is created for the customer. * Customer Authentication: The customer authenticates with their financial institution using the Bridge widget. * Account Ownership Details Retrieval: Bridge securely retrieves the account ownership information. * Data Normalization: WALDO standardizes data formats. * Feature Extraction: Extracts features from both the verified identity and bank account data. * Machine Learning Models: Utilizes models to predict the likelihood of a match. * Weighted Scoring: Assigns weights to different features based on their significance. * Threshold Evaluation: Compares the weighted score against predefined thresholds. * Successful Match: Proceed with Paykey Generation. * Mismatch Detected: Error handling and user notification. ## Business outcomes ### **Identity to account** WALDO significantly improves security for merchants, financial institutions, and payment providers. Its advanced name matching technology ensures that only rightful account owners can link and use bank accounts for transactions, bolstering A2A (account-to-account) payment flows by verifying ownership in real time. Beyond initial account connection, Waldo continuously verifies ownership over the lifecycle of a connected account, detecting changes in legal names or multiple authorized users. This constant vigilance reduces the risk of account takeovers and safeguards against fraudulent connections. ### **Fraud prevention** Waldo acts as a frontline fraud detection tool by instantly spotting mismatches between verified identity details and bank-account ownership records. Subtle name variations associated with legitimate users are correctly recognized, whereas truly inconsistent identities are flagged before transactions occur. Because Waldo accurately accommodates name variations, it also reduces false positives in traditional fraud-detection systems. Straddle can maintain high security standards without unduly inconveniencing legitimate customers. ### **Reduced friction** Despite its sophisticated security, Waldo remains invisible to legitimate users: 1. **Identity Verification**: Straddle ID confirms the user’s identity upon onboarding. 2. **Bank Connection**: The user authenticates with their financial institution via Straddle Bridge. 3. **Name Matching**: Waldo automatically compares the identity data to account ownership details in under 100ms, ensuring continuity and generating a reusable, secure “paykey” token if a match is confirmed. Customers enjoy a frictionless experience while benefiting from heightened security measures. ### **Regulatory compliance** Waldo underpins compliance efforts with regulations such as KYC (Know Your Customer) and AML (Anti-Money Laundering). By ensuring accurate identity matches and reducing false positives, it eases investigation workloads, streamlines watchlist checks, and empowers organizations to focus resources on genuine risks. Waldo’s refined approach also supports ongoing customer due diligence by detecting subtle naming inconsistencies that might indicate attempts to bypass controls. ## **Future enhancements** Straddle continues advancing Waldo to meet emerging demands: * **Broader Cultural Support**: Enhancements for diverse naming conventions (e.g., Hispanic structures, transliterated non-Latin scripts, multi-part names). * **ML-Enhanced Algorithms**: Integrating LSTM improvements through real-world usage feedback, creating a hybrid rule-based and machine-learning-driven system. * **Custom Threshold Configuration**: Allowing different similarity thresholds for specific risk tolerances or business contexts (e.g., stricter compliance vs. customer onboarding). * **Name Standardization API**: Providing configurable tools to unify naming conventions across systems, with cultural nuance to avoid “one-size-fits-all” formatting. These future capabilities underscore Straddle’s commitment to delivering the industry’s leading solution for name matching in increasingly global and digital markets. ## Frequently asked questions WALDO accommodates various cultural naming conventions by recognizing different name orders, handling multiple surnames or given names, and using phonetic and linguistic models to interpret names accurately. WALDO accounts for minor discrepancies and variations. If the differences are within acceptable thresholds, the algorithm can still determine a match. Significant discrepancies may result in a mismatch, requiring customer verification. Yes, WALDO adheres to data protection regulations such as GDPR and CCPA. It uses data minimization principles, and all personal data is encrypted and handled securely. WALDO is optimized for real-time processing and does not introduce noticeable latency. It operates transparently, ensuring a seamless user experience. WALDO's machine learning models are regularly updated to incorporate new data and improve accuracy, adapting to emerging patterns and trends in identity data. ## Conclusion WALDO offers a dynamic solution to the challenges of accurately matching personal names in modern payment systems and data-driven environments. The algorithm synthesizes advanced linguistic processing with domain-specific rules, delivering high accuracy and real-time performance. Architecturally, Waldo embodies best practices in software design: cleanly layered, modular, and cloud-native. Comprehensive monitoring and logging tools further ensure reliability in production. From a business standpoint, Waldo drives tangible value by increasing data quality, improving the customer experience, mitigating fraud, and streamlining compliance processes. As digital transformation accelerates worldwide, name matching plays a pivotal role in ensuring secure and reliable account-to-account payments across industries. ## Additional resources * [API Reference](/api-reference/introduction) * Integration Guides: * [Pay by Bank Guide](/guides/resources/sandbox-paybybank) * [Bridge and Paykeys Guide](/guides/bridge/overview) * Support: For assistance, contact [support@straddle.com](mailto:support@straddle.com) * [Community Forums](https://strddl.co/mmunity) Thank you for taking the time to learn about WALDO. We are committed to supporting you in delivering secure and efficient payment solutions. # ACH payments basics Source: https://docs.straddle.com/help/ACH101/ach-basics Learn how the Automated Clearing House (ACH) Network works, including key participants like ODFIs and RDFIs, and how electronic payments are settled. ## What is the ACH Network? The Automated Clearing House (ACH) Network is an electronic payments network used by individuals, businesses, financial institutions, and government organizations. It allows funds to be electronically debited or credited to checking accounts, savings accounts, financial institution general ledger accounts, or loan accounts. The ACH Network serves as the backbone for electronic money movement and related data, providing a safe, secure, and reliable network for direct consumer, business, and government payments. The ACH Network operates as a same-day, batch processing, store-and-forward system. Financial institutions store transactions throughout the day and process them at specified times in batch mode. The network exchanges funds and payment-related information throughout the United States, its territories, and internationally. ## ACH participants Five key participants contribute to the successful completion of an ACH transaction. Understanding each participant's role helps financial institutions better understand their position in the system. The company or business authorized by the Receiver to credit or debit an account. Originators initiate both credit transactions (like payroll) and debit transactions (like bill payments). An individual or company that has authorized the Originator to credit or debit their account. This could be an employee receiving payroll or a business partner receiving payment. The Originating Depository Financial Institution has a contractual relationship with the Originator for ACH services and sends ACH entries into the network on the Originator's behalf. The Receiving Depository Financial Institution maintains the Receiver's account relationship and posts ACH entries to the Receiver's account. ### Authorization requirements Authorization is a key component of an ACH transaction, giving the Originator authority to send credit or debit transactions to the Receiver's account. The authorization method varies based on transaction type. For detailed information about obtaining proper authorization, see our [Payment Authorization Guide](/help/Payment-Compliance/ach-auth) which covers specific requirements for [SEC codes](/help/Payment-Compliance/sec-codes) and different payment types. ### ODFI responsibilities and liability The ODFI carries the greatest liability of all ACH Network participants through warranties outlined in the ACH Rules. The contractual relationship between the Originator and ODFI outlines rights and responsibilities and provides the ODFI with mechanisms to pass appropriate liabilities to the Originator. **Example**: The ODFI warrants that transactions are properly authorized, yet the Originator obtains and maintains this authorization. Therefore, the agreement between Originator and ODFI must address the Originator's authorization responsibilities. ### ACH Operator The ACH Operator serves as the central clearing facility for ACH transactions. Key responsibilities include: * Accepting ACH entry files from ODFIs * Sorting, batching, and forwarding entries to the Receiver's financial institution * Performing editing functions to ensure mandatory information is included Two ACH Operators currently exist: the Federal Reserve Bank and EPN (Electronic Payments Network). ### RDFI responsibilities The Receiving Depository Financial Institution has several primary responsibilities: * Post ACH entries to the Receiver's account * Make funds available for credit entries or debit accounts on the Settlement Date * Provide transaction information to Receivers on their statements * Return ACH entries within specified timeframes when transactions cannot be posted ### Additional network participants **Third-Party Service Provider**: A party that performs ACH processing functions on behalf of the Originator, ODFI, or RDFI. Payroll processors are common examples. **Third-Party Sender (TPS)**: An entity with a contractual relationship with an ODFI to transmit debits or credits to a Receiver's account on behalf of the Originator, specifically when there's no direct agreement between the Originator and ODFI. To distinguish between Third-Party Service Providers and Third-Party Senders: if the Originator has an agreement with an ODFI and uses a payroll processor to create ACH files, the processor is a Service Provider. If the Originator contracts with the payroll processor who then sends files through their own financial institution, the processor is a Third-Party Sender. ## How the ACH Network functions The ACH Network operates through a systematic process involving all participants. For a more detailed explanation of this process, see [How does ACH work?](/help/ACH101/ach-basics#how-the-ach-network-functions). The Originator obtains authorization to initiate a transaction or provides notice to the Receiver that a transaction will be initiated. The Originator creates an ACH transaction file and presents it to their ODFI. The ODFI collects ACH files from Originators, verifies file validity, and transmits files to the ACH Operator at specified times. The ODFI may consolidate individual files into larger batches and retain "on-us" entries for their own account holders. The ACH Operator receives files from ODFIs, edits them for proper formatting, and distributes entry files to the appropriate RDFI. The RDFI receives entry files from the ACH Operator and posts entries based on Settlement Date and account number. Receivers get periodic statements with descriptive transaction information including date, amount, Originator name, and transaction description. ## ACH funds settlement Settlement represents the actual transfer of funds between financial institutions to complete ACH entry payment instructions. ACH settlement can only occur on banking days. The Federal Reserve Bank provides settlement services for both the Federal Reserve ACH Operator and private sector ACH Operators (currently only EPN). ### Settlement timing and dates The Federal Reserve Bank calculates net debit and credit positions of financial institutions and applies those debits or credits to the institution's account or their correspondent financial institution's account. Settlement timing depends on: * **Effective Entry Date**: The date the Originator intends for entries to post to Receiver accounts * **Delivery time**: When the file reaches the ACH Operator When the ACH Operator processes an ACH file, it reads the Effective Entry Date and assigns a Settlement Date. In most cases, the Settlement Date matches the Effective Entry Date, but the Settlement Date could occur after the Effective Entry Date if: * File delivery is untimely * The date is stale * The Effective Entry Date falls on a weekend or holiday ### Processing timeframes Since inception, the ACH Network's standard settlement period has been one to two business days after processing: * **Debit entries**: Can be sent one day in advance of the Effective Entry Date * **Credit entries**: Can be sent up to two days in advance of the Effective Entry Date Originators now have access to [same-day processing](/help/ACH101/same-day-vs-standard-ach) and settlement for eligible ACH credit and debit payments, while the standard processing environment remains available. # What is an ACH credit? Source: https://docs.straddle.com/help/ACH101/ach-credit A complete guide to ACH credit transactions: what they are, how funds move from sender to receiver, common use cases, and how they differ from ACH debits. Most Americans receive an ACH credit two or three times a month without knowing they've done so. The ACH system is a great unsung part of America's financial plumbing, and even frequent commercial ACH users can fall behind the pace of new solutions being built atop the underlying infrastructure. Despite not being a household name, ACH credit payments are quietly ubiquitous. Often referred to by informal names matching popular use cases (e.g., "direct deposit" and "peer-to-peer payment"), the ACH network powers tens of millions of credit transactions every day. **Impactful ACH credit usage statistics include:** * 11.6 billion ACH credit transactions per year * \$30.2 trillion in total value exchanged * 35 ACH credit transactions per person in the US * \~94% of Americans paid wages/salary by ACH credit * 11,000+ banks and credit unions in the US can receive ACH credit *Source: Nacha* ## What are ACH credit payments? An [Automated Clearing House (ACH)](/help/ACH101/ach-basics) credit payment occurs whenever someone instructs the ACH network to "push" money from their account to someone else's. In the Straddle API, ACH credits are processed as [**payouts**](/api-reference/payouts/create). This could be an employer (often via some processing partner) pushing payroll (direct deposit) to their employees, or a government agency pushing cash payments to eligible citizens. It could also be a consumer digitally paying a bill, buying something online, or initiating a peer-to-peer transfer to a friend through a service like Venmo or CashApp. ACH credits essentially move money from one bank account to another easily and inexpensively—from as fast as a few hours to as long as a few business days—all with just a name, bank account number, routing number, and basic transaction details. ## How do ACH credits work? For the person sending funds, an ACH credit transaction is the digital version of a paper check. Instead of filling out a piece of paper for the payee to bring to their bank, the payer instructs the ACH network to move money between their accounts directly. Here is how ACH credits work mechanically: The payer or their processing partner gives an Originating Depository Financial Institution (ODFI) the payee's account information, the amount to be sent, a categorization code, and a target settlement date. The ODFI or an approved processing partner passes on these requests to the ACH network in periodic batches. Five times each business day, the ACH network breaks down these incoming bundles into individual messages (transactions) and rebundles them into new batches for immediate delivery to each Receiving Depository Financial Institution (RDFI) that holds payee accounts. Each RDFI then imports their incoming batches into their system, executes all the transactions they can based on the processing window requested, and sends back any error codes with their next regular batch. If no error/return code is received by the requested settlement time, the ODFI and RDFI settle the transaction using their balances at the Federal Reserve. Funds for settled transactions are then released by the RDFI to the payee. Depending on when the first messages are sent and/or whether the ODFI pays the extra fee for [same-day processing](/help/ACH101/same-day-vs-standard-ach), it generally takes two business days for credits to reach payees. # What is an ACH debit? Source: https://docs.straddle.com/help/ACH101/ach-debit A thorough guide to how ACH debit transactions work, what they are used for, and how they differ from other types of debit transactions The [ACH (Automated Clearing House) network](/help/ACH101/ach-basics) is an interbank messaging system for transactions involving US bank accounts, built in the 1970s to negate the need for paper checks. ACH is the main way that financial institutions organize the movement of money in and out of personal accounts. When money is being moved out for things like a purchase or bill payment, it's typically an ACH debit transaction at work. ## What is ACH debit? Any ACH transaction structured as an ACH debit "pulls" money from one account and moves it to another—such as from a consumer's personal account to that of a business or government agency. In the Straddle API, ACH debits are processed as [**charges**](/api-reference/charges/create). The ACH network constantly takes in batches of push and pull requests from banks and their intermediaries. Then, five times per business day, the network sorts them into new bundles and delivers them accordingly. When a given request in one of those new batches asks that an account be debited some amount of money, that's an ACH debit request. Every transfer requires pulling money from someone's account, meaning a debit is always happening on one side or the other. Whether it gets categorized as an ACH debit depends on who initiated the request. For most consumer billing scenarios, the biller is the one initiating (or "originating") the ACH request. And because that request is for the system to pull money, it's considered an ACH debit. If, instead, a consumer sends money as a one-off transfer from their online banking portal, they're asking the network to "push" money for them. This means it's not an ACH debit—despite money being debited from their account. ## How does ACH debit work? In an ACH debit transaction, one party agrees to pay another. To make that happen, the party receiving payment sends a message to the ACH network asking it to collect said payment and move the funds into their account. The payee (aka the originator) or their processing partner gives an Originating Depository Financial Institution (ODFI) the payer's account information along with the amount to be debited, a categorization code, and a target settlement date. The ODFI (generally a bank) or the processing partner then passes these requests on to the ACH network. 5x per business day, the ACH network breaks down these incoming bundles into individual messages (each representing a transaction) and rebundles them for quick delivery to each Receiving Depository Financial Institution (RDFI). Each RDFI imports their mail into their system, executes or queues all the transactions, and sends back any error codes with their next regular batch of mail. If no error/return code is received by the requested settlement time, the ODFI and RDFI settle the transaction using their balances at the Fed. Funds for settled transactions are then released by the ODFI to the payee. These debits can take just one business day, depending on when the first messages are sent and/or whether the ODFI pays for same-day processing. However, some error codes can require reversal, as the RDFI has two business days to inform the ODFI of certain problems. ## Main types of ACH debits The ACH system supports different types of debit. Each is identified by its own [Standard Entry Class (SEC) code](/help/Payment-Compliance/sec-codes) representing a specific use case. Converting physical checks received by mail or drop-box into ACH debit transactions. Converting physical checks received from the payer in person into ACH transactions some time after they're received. Debiting bank accounts to settle ATM withdrawals. Immediately converting physical checks received in person from the payer into an ACH transaction, where the check is voided and immediately returned. Debiting bank accounts for card payments made via an electronic terminal. Directly debiting bank accounts for pre-authorized bill payments. Requires proper [authorization](/help/Payment-Compliance/ach-auth) from the account holder. Electronic terminal payments (for ACH-linked debit cards) within a shared network. Debiting bank accounts for transactions originated over the phone. Debiting bank accounts for transactions originated online. See our guide on [Internet vs Contract authorization](/help/Payment-Compliance/consent-types) for compliance requirements. ## Is ACH debit related to debit cards? While the ACH network can be used to settle transactions initiated by debit cards, its design doesn't allow for transactions to be authorized in real-time. Cases that require on-the-spot balance verification and debiting must happen by other means. Debit cards use a separate real-time network for authorization, which ensures that funds are successfully decremented from the purchaser's account before ATMs/merchants need to hand over cash or valuable products. ACH debit transactions are then often used to move those funds from bank to bank to finalize the transaction. There are now also non-card-based solutions that can similarly get around ACH's speed constraints. For example, users of Plaid-connected apps can choose to share their account balance information, which can confirm whether they have enough funds for an ACH debit transaction. ## How are eChecks different from ACH debit? eChecks are generally paper checks that have been manually converted into ACH debit requests. However, the term can also represent the idea of ACH transactions as "a digital replacement for the paper check," where no physical check is ever used. Most mobile banking apps enable customers to capture paper checks via their phone's camera. Those apps might then strip the relevant info and create ACH requests, or simply forward the digital scans to a traditional check-clearing facility. The words "do not convert to ACH" are written on some checks where preserving those scans is desired. Virtually all checks are now converted electronically at some point in the processing journey; whether they end up as ACH debit requests is up to each individual financial institution. ## Is there a better way to use ACH debit? The ACH system, though quite safe, was built with classic tradeoffs in mind. It's relatively slow, and there are certain downsides due to the lack of real-time data transmission. ### Primary challenges with traditional ACH debits Whether because of a mistaken input or because of a fraud attempt. Debit request is returned due to insufficient funds. Fraudulent reversals of ACH debits by customers attempting to take back money paid for a good or service already received. ### Solutions for enhanced ACH Solutions that can help businesses alleviate these risks in real-time include: * **Instant account verification** to check that account information is valid for online debits * **Balance checks** to ensure enough funds are available * **Transaction histories** that enable them to look for patterns that could indicate fraud (see our [Glossary](/help/Reference-Materials/glossary) for more about Straddle's **Watchtower** fraud detection) The ACH network is essentially the base option for money transfers in the US, on which other services can be layered to obtain the results and safety desired. ACH debit transactions in particular can be made substantially less risky with the help of enhanced ACH solutions, making them the rough equivalent to real-time products at significantly lower costs. # ACH vs Wire Transfers: What's the difference? Source: https://docs.straddle.com/help/ACH101/ach-wire Compare ACH transfers and wire transfers across speed, cost, settlement timing, and reversibility to choose the right rail for your business payments. There are four principal systems for digitally exchanging money in the US, two of which don't involve the use of a card: the ACH transfer and the wire transfer. While the advantages of the latter are more widely understood, the former is primarily known both by other names and by a reputation that no longer fits it. This article defines what ACH and wire transfers are, explains the differences between them, and explores how they're changing. ## What's ACH? The Automated Clearing House (ACH) network is a system for moving money between bank accounts in the US. It's the direct evolution of the paper check—just transformed into a digital process to improve efficiency and reduce the need for human inputs. It's often referred to by functional nicknames like direct deposit, direct debit, auto-pay, and the generic term "bank transfer". It's also the underlying technology behind most peer-to-peer transfers made through services like Venmo, PayPal, Cash App, and Zelle. ACH transfers can occur between any two financial institutions on the network, and can either push or pull money through the system as needed. Each transaction is submitted to the network as part of a batch, which the network's operators repackage into new bundles for each receiving institution 5 times per business day. The party initiating the request can either choose to pay for same-day service or default to one business day (for debits being pulled through) or two business days (for credits being pushed through). ## What's a wire transfer? Wire transfers, named after their origin in the days of the telegraph wire, are direct point-to-point transfers between any two financial institutions; or, for international wires, sometimes with one or two intermediaries along the way. Sometimes called remittance transfers, they're typically used for higher-value items like property purchases or for settling large institutional transactions. Both ACH and wire transfers work on similar principles for clearance and settlement, just with different timelines and rules. Where wires generally clear immediately and forever, ACH messages are slowed down both by the batching mechanism and by various error messages (if something goes wrong with the transaction). These messages can take up to a few business days to be returned to the originator. Sending and receiving banks in both systems also settle their transactions with the help of the Fed, just on different schedules. In both systems, funds are typically released to recipients shortly following settlement. ## Key differences between ACH transfers and wire transfers There are seven major differences between ACH transfers and wire transfers, explored in detail below. **Terminology clarification:** "cleared" here means that the transaction details have been passed on, "settled" means the two banks have exchanged money to make good on the underlying transaction, and "disbursed" means the funds have been released to the end account holder. ### 1. Transfer speed differences **Wire transfers** typically clear within minutes and settle within a business day, while **ACH transfers** can take between hours and days to both clear and settle. Wire transfers are cleared as soon as the receiving bank signs off on the incoming message, which is either immediate or following any routine due diligence. If the sender paid a premium to use Fedwire, these transfers then settle and disburse immediately thereafter. If the payment was instead routed through CHIPS (Clearing House Interbank Payment System), the timeline will depend on when the transfer was initiated. If sent by the specific bank's mid-day deadline, it will typically settle early that evening. Otherwise, it will settle the next business day. ACH transfers are more variable. If the originator paid the extra fee for same-day processing and the transaction was initiated within one of the three same-day processing windows that occur each business day, then clearing, settlement, and disbursement will all happen that day. Otherwise, clearance will happen by the end of the current business day, and settlement either the morning of the next business day (for debit transactions) or that of the business day after (for credit transactions). Unless there is an error, disbursement happens within minutes to a few hours. ### 2. Settlement differences **Wire transfers** generally settle permanently, while some **ACH transfers** can be recalled up to 3 months later. Wire transfers can be cancelled up until they're cleared (which could be just minutes), then are largely irrevocable beyond that. The main exceptions are when the bank mistakenly sends the transfer to the wrong account or sends the wrong amount. In cases of sender's remorse, the sending bank is permitted to try to work with the receiving bank, but has limited recourse if the funds have already been withdrawn on the other end. ACH transfers can't be cancelled, but can be recalled or disputed: * **Credit transfers** can be requested to be reversed within five business days if sent to the wrong account, for the wrong amount, with the wrong date, or as a duplicate * **Debit transactions** can be disputed by the payer as non-authorized for up to 60 days after the statement date of the transaction in question * **Debit transactions** can also be returned because of insufficient funds for up to two business days ### 3. Cost differences When a consumer uses ACH to make or receive a payment, they almost always pay no fee. Instead, the organization or business they're transacting with incurs a fee from their payment processor or bank. However, if a consumer uses a wire transfer, the fee is charged to them in the same manner it would be charged to a business. | Transfer Type | Sender Fee | Receiver Fee | Additional Costs | | - | - | - | - | | **Domestic Wire** | Up to \$35 | Up to \$20 | - | | **International Wire** | Additional \$15-30 | Up to \$20 | Currency exchange fees | | **ACH Transfer** | Usually \$0 for consumers | Usually \$0 for consumers | Business fees: $0.01-$0.50+ per transaction | ACH transfer fees are highly variable, but generally quite inexpensive. Processing fees can be as little as tenths of a cent per transaction with banks and into the tens of cents or more with payment processors. Higher dollar-value transactions can also incur percentage-based fees with some processing partners of up to 1-1.5%, but those are usually capped at \$5. ### 4. Directional differences **Wire transfers** can only push money, while **ACH transfers** can either push or pull. * **Wire transfers** are purely credit transactions, moving money from the sender to receiver. This means only the sender can initiate * **ACH transfers** are bi-directional in that they also allow payees to initiate transactions on the behalf of payers. This makes them more suitable for more use-cases ### 5. Frequency differences **Wire transfers** are generally one-off only, while **ACH transfers** can be recurring. * **Wire transfers** are singular transactions by design (for consumers at least). Each new transaction generally requires a new authorization and a new fee * **ACH transfers** can allow for recurring transactions, making them attractive for regular billers and employers. Payers or employees can give standing authorization, allowing for inexpensive regular debit or credit transactions ### 6. Size differences **Wire transfers** are typically used for high-value transactions only, while **ACH transfers** are most often used for smaller and more frequent transactions. **Wire transfers** are much larger on average. Fedwire, which settles the majority of wire transfers within the US, handled $840 trillion in transfers in 2020 across 184 million transactions, for an average value of roughly $4.6 million per wire transfer. Though this is somewhat inflated, as many transactions initially clear through CHIPS and then settle on a netted basis later through Fedwire. **ACH transfers** are much more volume-heavy. The ACH network processed $62 trillion in transfers in 2020 across nearly 27 billion transactions, for an average value of $2,300. While the $100,000 maximum only applies to same-day transactions, the slower settlement time of the ACH network has historically made it more suitable for smaller transactions. 98% of ACH transactions are smaller than $25,000. ### 7. Global differences **Wire transfers** are widely used internationally, while **ACH transfers** are currently only used in the US and a few special bilateral agreements. * **Wire transfers** are broadly supported internationally, with a mature network of correspondent banks allowing transfers across countries and currencies with usually only one or two intermediary stops. Though currency exchange fees can be quite costly at 2-3% * **ACH transfers** are largely limited to the US. While there have been occasional pushes for more interoperability between major ACH-like networks globally, the number of parties required to coordinate this is quite high ## How are ACH transfers and wire transfers changing? After years as the leading incumbents for money transfer between banks, ACH and wire transfers are now both being renovated to allow for new and better user experiences. ### Wire transfer innovation Wire transfers are being reimagined by fintech companies like Wise, who've replaced traditional chains of correspondent banks with pools of money in each country. If someone in the US wants to send a wire to someone in Australia, they can send an inexpensive ACH transfer to Wise's US account instead. Wise will then send a local ACH-like transaction from their Australian account to the local recipient. Cutting out the middle parties saves a lot of money, which Wise passes on to its customers. ### ACH transfer improvements ACH transfers are getting faster and more efficient as new solutions are built on top of the old infrastructure. For example, Plaid and MX have tools that enable businesses to validate account information, verify account ownership, and ensure accounts have sufficient funds before an ACH transfer is initiated. These tools help innovators create new financial services solutions that leverage the ACH network. Wire transfers and ACH transfers serve different needs. Luckily for business owners, both user experiences are being improved, but especially ACH, as it's likely to get faster and easier for everyone. An example of this is the expansion of Same-Day ACH, which will soon increase its transaction limit from $100,000 to $1 million. This increase will make ACH a viable and cost-effective alternative to wire transfers for larger transactions. # Same Day ACH vs Standard ACH & Cut-off times Source: https://docs.straddle.com/help/ACH101/same-day-vs-standard-ach Compare same-day ACH and standard ACH processing windows, daily cut-off times, settlement schedules, and use cases for choosing the right option. Same-Day ACH processing allows merchants to send ACH [charges](/help/ACH101/ach-debit) ([API charges](/api-reference/charges/create)) and [payouts](/help/ACH101/ach-credit) ([API payouts](/api-reference/payouts/create)) faster than standard ACH processing. Historically, ACH payments have always been batched at the end of each business day (7pm ET) and sent to the Federal Reserve for overnight processing. Charges would show on the customer's bank account the next banking business day. Same-Day ACH processing was introduced by [Nacha](/help/ACH101/what-is-nacha) to allow [charges](/help/ACH101/ach-debit) and [payouts](/help/ACH101/ach-credit) to be effective on the same day they are submitted by a merchant, rather than the next day. Early processing cut-off windows were set up and new [ACH banking rules](/help/nacha-rules/ach-rules) were created to make this possible. Same-Day ACH makes the effective date of a payment the same day, but it does **not** mean funding events occur the same day. ## Standard ACH With standard ACH, each [ACH transaction](/help/ACH101/ach-basics) is cleared overnight. The sending institution (Straddle's sponsor bank) sends the transaction to the receiving institution (customer's bank aka RDFI). When the customer's bank receives the transaction, it has until the end of the next working day (48 hours) to send a [rejection](/help/nacha-rules/ach-return) to our sponsor bank. If our sponsor bank does not receive a return from the customer's bank by the morning of the third business day, then the transaction is deemed to be successful. ## Same-day ACH With same-day ACH, the effective date of the [charge](/help/ACH101/ach-debit) can occur the same day (rather than overnight/next day) as long as you hit one of the same-day ACH windows (noted below). The customer's bank still has two business days in which to send a [return](/help/nacha-rules/ach-return), but the effective date being the same day speeds up the funding event by a day. ## Benefits of Same-Day ACH processing * **Faster payouts**: Pre-funded payouts can be delivered to your customer, employees, sales agents, vendors, etc on the same day they are submitted to ACHQ. * **Priority access to funds**: Charges are deducted from your customers' accounts sooner than standard ACH processing, ensuring you have higher priority and faster access to the promised funds as well as shortening the ACH return window. * **Accelerated funding**: Funding events for Same-Day ACH charges hit your bank account one day sooner than standard ACH charges. ## ACH cut-off times | Processing Window | Cut-off Time | | - | - | | Same-Day ACH Window #1 | 9:00 AM EST | | Same-Day ACH Window #2 | 11:15 AM EST | | Same-Day ACH Window #3 | 2:15 PM EST | | Standard (overnight) ACH Window | 7:00 PM EST | The earlier a Same-Day ACH payment is delivered to the Federal Reserve, the sooner the payment posts to the receiver's bank account that day. # What is Nacha and is your business compliant? Source: https://docs.straddle.com/help/ACH101/what-is-nacha Learn what Nacha is, the rules it enforces for the ACH network, and the steps your business should take to stay compliant when accepting ACH payments. Over \$62 trillion in ACH payments passed through the Automated Clearing House (ACH) network in 2020. These transactions—direct deposits, bill payments, peer-to-peer transfers, and more—were all ultimately secured by the compliance of ACH participants to a detailed set of rules and standards as established and enforced by an organization called Nacha. This guide provides a detailed look at what Nacha is, its rules for ACH transactions, and how businesses can best comply with them. ## What does Nacha mean? Nacha was originally NACHA, an acronym for National Automated Clearing House Association. Though the acronym is no longer in official use (they go by 'Nacha' instead), it shows where the organization came from and the role they fill in the ACH ecosystem. Back in the early 1970s, regional banking associations across the US joined forces to standardize processes around the development of "automated" clearing house solutions—the digital replacements for physical clearinghouses where paper checks were once exchanged. By 1974, the American Bankers Association had centralized all of those regional groups under a national sub-division that they named NACHA. An independent organization since 1985, Nacha is effectively a non-profit consortium tasked with: * Translating federal legislation and executive rules into clear guidance for member banks and ACH network participants * Enforcing those rules for all 10,000+ member banks and network participants * Driving development and adoption of the ACH system * Acting as a trade organization (e.g., education, advocacy, roundtables, etc.) ## What's the difference between Nacha and ACH? The Automated Clearing House (ACH) network is the American interbank funds-transferring system run by two national operators: The Clearing House and FedACH. Nacha is the governing body that oversees the ACH network. It ensures that member banks are aware of and compliant with related federal legislation, along with promoting development and education around ACH. ### ACH Network Operators The Clearing House (also referred to as TCH or PayCo) is itself another banking consortium, with a much smaller subset of the major US banks (currently 24). They run a system called Electronic Payments Network (EPN), which is the ACH operator for all private banks in the ACH network. FedACH is part of the Federal Reserve system, performing the same function as EPN, for government accounts and entities, rather than private ones. When an ACH transaction involves both a government account and a private account, the two operators work together to pass the corresponding data between themselves accordingly. Nacha translates mandates from the US government into actionable rules and standards for The Clearing House and FedACH, which then operate their respective parts of the ACH network in accordance with Nacha's guidance. Nacha also mediates between members and acts as an advocate for the ACH ecosystem to the larger financial industry. ## Who do Nacha rules apply to? Nacha's rulebook is a living document that outlines binding rules for all 10,000+ members that collectively represent the overwhelming majority of retail banks and credit unions in America. The rules also extend down to all ACH network participants including payment processing partners, businesses, and even individuals that use the ACH network. "The Rules ensure that millions of payments occur smoothly and securely each day. The Rules direct how the ACH Network is operated, keeping it safe and efficient. The Rules standardize the roles and responsibilities of all parties using the ACH Network, ensuring that all ACH payments are handled on a level playing field." - Nacha ## What are the main Nacha requirements? The Nacha rules are a guiding framework for the ACH Network and include the basic obligations of each ACH network participant. According to Nacha, understanding the rules helps to ensure efficient payments, better risk management practices, and reduces chances of returns. ### Core principles While Nacha charges a fee for its full rulebook, the driving principles behind its rules and standards are: Work from a shared understanding of formatting, timelines, and mutual expectations. Use appropriate due diligence to minimize system abuse, especially for ACH debit requests and reversals. Safeguard all consumer data to prevent theft, internal misuse, and/or accidental leakage. Adopt new measures within the recommended timelines to ensure that core innovations are reliably and equally distributed to all users. ### Main requirements Some of the main requirements and rules that follow these principles include: Member banks are prohibited from sending, receiving, or storing unencrypted information. Any necessary hard copies also have to be stored securely, with access restricted to narrowly defined legitimate business purposes. The specific details of these policies also need to be clearly documented for consumers. Organizations initiating requests to the ACH network have to take reasonable steps to make sure they've both verified the identity of the customer being debited and gained explicit authorization. For debit transactions, businesses also need to securely store proof of authorization for at least two years. And if the amount of a recurring debit (e.g. automatic bill payments) changes, this must be communicated to payers with "appropriate notice" to give them a chance to rescind their authorization. Organizations initiating ACH transactions over the internet (which are referred to as WEB debits) need to do what's "commercially reasonable" to screen transactions to detect and deter fraud. At a minimum, they need to ensure that bank account details are valid before using them. Originating Depository Financial Institutions (ODFIs/the bank initiating the ACH request) are responsible for ensuring that all recurring debits are cancelled promptly upon customer request; and that any changes to amounts or withdrawal dates are communicated transparently and with adequate notice. ## Why is Nacha compliance important? In the narrow sense, Nacha compliance is important because rule-breaking organizations will likely encounter more errors and returns in their ACH transactions and could get fined by the ACH network. In the larger sense, complying with rules and standards that are intended to ensure a safe and effective ACH network is good for all who participate in the ACH ecosystem—promoting its healthy use and sustainable growth. There are two main drivers for staying compliant with Nacha rules and requirements: ### Avoiding downsides If a business continually violates Nacha's rules and causes high error rates, their bank may fine them and potentially discontinue their business relationship. Additionally, organizations relying on outdated processes that aren't Nacha-compliant are also less likely to complete transactions without errors and returns; or effectively screen for fraud. ### Promoting upsides Whenever an ACH network participant falls behind on the rules and standards, there's going to be a resulting customer service failure. Some will be getting a worse-off deal than they ought to receive, while others might experience payment failure altogether. Every bad experience with the system sours perceptions of ACH, which is bad for the ACH ecosystem as a whole. In contrast, every positive experience improves the system's reputation, which is good for both adoption and consumer satisfaction. ## Are there ways to make Nacha compliance easier? For organizations that rely on the ACH network, the best way to streamline Nacha compliance is to quickly and effectively verify account and routing numbers and whether the account is in good standing—before initiating an ACH transaction. This is a necessary step to comply with Nacha's account verification and fraud mitigation requirements, and certain account verification methods make compliance easier and more pleasant for users than others. ### Nacha-approved verification methods There are currently five Nacha-approved ways to verify a consumer's banking details: | Method | Description | Speed | | - | - | - | | Microdeposits | Small test deposits to verify account ownership | Multiple days | | Manual Validation | Manual verification of account information | Multiple days | | Pre-notes | Zero-dollar test transactions | Multiple days | | Database verification | Cross-reference with banking databases | Multiple days | | Instant Account Verification | Real-time verification | Instant | Other than Instant Account Verification, these methods generally take multiple days to complete and require customers to provide information they likely don't have on hand (e.g. a voided check or account and routing numbers). This causes them to be slow, error prone, and a poor user experience. # Why businesses choose ACH payments Source: https://docs.straddle.com/help/ACH101/why-ach Learn how ACH payments provide a cost-effective solution for various business use cases and why companies are increasingly adopting this payment method When it comes to payments, businesses have more options than they might realize. ACH payments present a cost-effective solution for many use cases. Automated Clearing House (ACH) is the dominant payment rail for many types of transactions in the US, such as paying taxes, paying employees, and paying suppliers. However, it's increasingly being used for accepting payments as well. This article covers the various use cases for ACH payments, why businesses choose ACH over other methods, and how to get started with accepting ACH payments. ## What do businesses use ACH payments for? ACH is a versatile tool that works for a multitude of business use cases. While it has been traditionally slow to pick up steam in certain areas, such as point-of-sale (POS) payments, it has been the dominant payment method for others, such as businesses paying their employees. Direct deposit via ACH is the way 93% of employees get paid. It's also growing fast in other use cases, such as peer-to-peer (P2P) payments, where it saw a 42.2% year-over-year volume growth from 2019-2020. Common use cases for ACH in business include, but are not limited to: ### Funding customer accounts For businesses that offer brokerage or financial accounts—whether that be for trading stocks and cryptocurrencies or for storing funds on a digital wallet—ACH is a viable and cost-effective option for getting customers to fund their accounts. Once a customer shares and verifies their external bank account information (from which they fund the new account), they can quickly add the desired amount of funds and add more funds from that external account at any point in the future. ### Enabling customers to move funds Once a customer funds a financial account such as a digital wallet, they will want to spend some of that money. Whether it be for peer-to-peer (P2P) payments or buying goods and services, ACH is a reliable, safe, and easy way for customers to move (or spend) their funds. That's why it's one of the popular methods used by P2P payments platforms like Venmo. ### Accepting payments ACH is used in payments for a variety of goods and services. One example is a chain of gas stations and convenience stores that uses SmartPay Rewards, a mobile app for ACH payments. Customers can pay ahead of time or at the store, and merchants pass on the savings from lower ACH fees in the form of discounts and rewards. Catch is another example of a platform that enables ACH payments. When Catch users pay with their bank at various e-commerce sites, they earn up to 10% store credit as they help the merchants save on credit card fees. ### Billing and recurring payments Direct debit, also known as 'auto-pay', is a widely-used tool for businesses to accept regularly recurring payments, such as those for monthly bills like online newspaper subscriptions or insurance premiums. Once businesses get customers to authorize ACH direct debits, they have a cost-effective, reliable, and hassle-free way to collect recurring payments for as long as they remain a customer. ### Paying employees Most US-based employers use ACH direct deposit to pay their employees directly from bank to bank. Direct deposit reduces administrative overhead as payments are run in large batches, and is much easier than writing checks. Direct deposit payments can typically be set up in payroll software and require employees to give authorization and share their account and routing information. ### Paying suppliers Some business-to-business suppliers that used to take paper checks have switched to ACH. This helps them reduce the administrative overhead and waiting time for checks to arrive by mail. ### Moving internal funds Businesses often have multiple bank accounts for different purposes, and sometimes with different banks. Using ACH to move money between accounts is more cost-effective and efficient than other methods, such as wire transfers or writing checks. ## Why many businesses choose ACH While some will assume customers only want to pull out their credit or debit cards when it's time to pay, that's simply not true. The growth in ACH in areas like internet-initiated payments (15% volume growth in 2020) shows this. Aside from the significantly lower costs compared to credit cards and wire transfers, ACH benefits businesses in several ways. ### User experience 'Pay with your bank' options are, in most cases, just as easy or easier to use than credit cards. In fact, with credit cards, consumers are often tasked with manually entering not only their credit card number, but also its expiration date, the card verification code, and their address. Modern tools such as Plaid or MX's instant account authentication make ACH much easier than credit card entry. Instead of entering their account and routing numbers, users only need to enter their online banking credentials. Reducing friction in this way can increase the percentage of customers that complete the payments or account funding sign-up process. ### Lower costs The strongest motivator for businesses to use ACH is the cost. ACH costs aren't set in stone, as various processors and banks charge different fees. They can also charge a premium for faster settlement times, such as with same-day ACH. **Cost comparison:** * **ACH**: Fees can be as little as tenths of a cent per transaction or in the tens of cents for businesses with lower ACH volume. Some payment processors may charge a fee of up to 1-1.5% for larger transactions, usually with a cap of \$5. * **Credit cards**: Charge a percentage fee between 1.5-3.5% * **Wire transfers**: Typically cost up to $35 for the sender and $20 for the receiver ### More options When businesses offer a 'pay with your bank' ACH option alongside credit and debit cards, they're giving customers the option to choose what works best for them. Having ACH as a choice reduces barriers for some customers, as not all of them have a credit card due to a lack of credit history or unwillingness to potentially go into debt. ### Reduced churn Due to the fact they're either lost, stolen, or expire, credit cards have a typical shelf life of **3 years**. Bank accounts, on the other hand, are used for an average of **14 years**. Once a business is connected to a customer's bank account for ACH payments, it's unlikely that they'll experience payment churn for quite some time, which reduces drop-off and increases revenue over the long term. ## Why would a business choose credit cards over ACH? While there are some obvious advantages to ACH, there are still compelling reasons to accept credit cards, or both methods at the same time. For some use cases, such as point-of-sale (POS) transactions, credit cards can be a great choice, despite the higher fees. ### Instant settlement For businesses that accept a high volume of one-time payments either in a store or online, it can make sense to skip the onboarding process that ACH requires and go straight for the credit card. This is mainly due to the fact that credit card payments settle instantly, allowing a business to reliably accept payments from anyone. Credit cards do come at a higher cost and risk of fraud. According to a Fed survey, ACH has the lowest fraud risk of any payment rail. ### Consumer preferences While credit cards are familiar and universal, most consumers aren't quite used to the idea of 'paying with their bank'. In fact, if a business only offered ACH and not credit cards, it might turn a good number of consumers away. However, recent trends show that alternative payment methods—such as P2P payments apps like Venmo—are becoming increasingly popular, especially among younger generations. **79% of Gen Z consumers use P2P payments platforms at least once a month**, indicating a future shift towards other types of payments. ## Three steps to get started with ACH Countless businesses use ACH to accept payments, and getting started isn't difficult. Here are three steps that any business looking to collect ACH payments can take: In order to onboard new customers to make ACH payments, a business needs to verify that their customer's account numbers are valid and the account is able to complete ACH transfers. The traditional way to achieve this was to have the customer manually verify microdeposits or provide a voided check for later verification (both of which can take several days to complete). However, new methods like instant account authentication have drastically reduced onboarding time and make ACH more secure. Choose Straddle. How a business adds ACH to its payment flow will depend on the use case, which could be recurring subscription payments, new customer account funding, accepting one-time payments, or something else. They'll need to work with their authorization and payment providers to find the best ways to create a frictionless ACH onboarding and payment flow that converts at a high rate. ### Example ACH payment flow An example of an ACH payment flow with a business that uses Plaid or MX could look like this: 1. The customer chooses 'pay with my bank', 'set up auto-pay', or 'fund new account', depending on the use case 2. After a short informative message that shares the business uses Plaid, Plaid Link launches showing Plaid's consumer privacy policy. The customer consents to the connection by selecting their bank and entering their online banking credentials, which securely and instantly connects their account 3. Once their account is successfully authenticated and connected, customers can use ACH to pay, fund an account, or set up automatic payments, which is handled by the ACH processor on the back-end ## Is ACH the future of payments? As businesses seek to offer their customers more options to pay in a way that works for them, more are going to look at ACH as a viable new option. This is already happening across many areas, as the total value of ACH transactions rose 8.9% in 2019 and another 10.8% in 2020. In the future, it's reasonable to expect more 'pay with your bank' options, especially in mobile and online shopping. For businesses that want to save on credit card fees and provide an alternative payment method that some consumers might prefer (and are increasingly getting used to), ACH makes sense. # Bank Account Verification Requirements Source: https://docs.straddle.com/help/Payment-Compliance/account-validation Understand Nacha's WEB debit account validation rules and compliance requirements for businesses accepting internet-initiated ACH payments from consumers. Companies that accept [ACH payments](/help/ACH101/ach-basics) over the web are now subject to heightened validation requirements. Ensure your business stays compliant with [Nacha's](/help/ACH101/what-is-nacha) current regulations. ## What is Nacha? Nacha was originally NACHA, an acronym for National Automated Clearing House Association. Though the acronym is no longer in official use, it shows where the organization came from and the role they fill in the ACH ecosystem. Back in the early 1970s, regional banking associations across the US joined forces to standardize processes around the development of "automated" clearing house solutions—the digital replacements for physical clearinghouses where paper checks were once exchanged. By 1974, the American Bankers Association had centralized all of those regional groups under a national sub-division that they named NACHA. An independent organization since 1985, Nacha is effectively a non-profit consortium tasked with: * Translating federal legislation and executive rules into clear guidance for member banks and ACH network participants * Enforcing those rules for all 10,000+ member banks and network participants * Driving development and adoption of the ACH system * Acting as a trade organization (education, advocacy, roundtables, etc.) ## Online ACH volume is growing fast The volume of online ACH payments is quite large and growing fast. ACH has long been a staple for larger, more regular payments—such as Direct Deposit wages and Direct Payment of utility bills—but its prevalence in other, smaller transactions is on the rise. Much of this growth has come from internet-initiated ACH transactions, also referred to as **[WEB debits](/help/Payment-Compliance/sec-codes)**. There are many types of ACH transfers that happen online—mainly payments for bills such as mortgages, credit cards, and utilities, but also some high-ticket retail goods. Internet-initiated ACH transactions grew by 15% in 2020, highlighting the rapid adoption of online payment methods. As transaction volumes rise, [Nacha](/help/ACH101/what-is-nacha) has implemented a new rule, known as the **Web Debit Account Validation Rule**, that affects those who accept internet-initiated [ACH payments](/help/ACH101/ach-debit). This rule adds to the existing screening requirements that account validation should be included as part of a reasonable fraudulent detection system. ## What is Nacha's 2021 rule change? Nacha's 2021 rule change is specific to [WEB debits](/help/Payment-Compliance/sec-codes) (internet-initiated transactions) and increases the standards for detecting fraud. Specifically, ACH originators of WEB debits now must use a "commercially reasonable fraudulent detection system" that includes "account validation" for the first time use of an account number or for any change to previous account numbers. Businesses that use [ACH](/help/ACH101/ach-basics) to [debit](/help/ACH101/ach-debit) consumer accounts via online/mobile requests must validate that new accounts are legitimate, open, and able to receive an ACH transfer before their first use. In Straddle, this validation is handled automatically through our [Bridge](/help/Reference-Materials/glossary#bridge) account connectivity suite. ### Key requirements At a minimum, businesses must validate that new accounts are: * Legitimate * Open * Able to receive an ACH transfer before their first use Nacha does not recommend any specific method for validating account information, but there are several ways to achieve this, including microdeposits, manual validation, database verification, and instant verification via API. ### Implementation timeline Originally the rule was going to take effect on January 1, 2020, but was pushed back to March 19, 2021, to give more time for guidance and education. The rule only applies to new accounts; already established accounts do not need to be re-validated. Additionally, originators are only required to validate the account information, not ownership. ## Why did Nacha change the rules? This rule change is part of a larger, ongoing effort to address fraud attempts and data quality. It aims to ensure accounts are valid and eliminate data entry errors related to account numbers, bringing to the forefront a requirement that has been in the Nacha guidelines for many years. ### ACH fraud statistics ACH fraud is relatively rare. In fact, it has the lowest fraud rate by value among all payment types, at **0.08 basis points** ($0.08 of fraud per $10,000 in payments), according to a Federal Reserve study that measured fraud rates from 2012-2015. By comparison, ATM and card payments fraud increased from 7.99 to 10.80 basis points during the same time period. However, the proliferation of ACH in fast-growing services—such as digital wallets and neobanks—underscores the industry's need to use commercially reasonable practices to ensure the continued safety of the ACH Network. ## Are your payments compliant? With the new rule in effect, the way that many businesses had accepted ACH payments in the past will no longer be possible. This includes businesses that simply ask customers to manually enter their account and routing numbers, but don't validate those accounts. Without the minimum step of making sure that the account is valid, open, and able to receive an ACH transfer, a business will not be in compliance with the new rule. The new rule does not affect existing customers that pay by ACH. It is only for new accounts or for those that have changed their bank account information via an online/mobile means. ## Account validation methods There are five different approaches to validating accounts under the new rule. These different approaches have a wide range in terms of speed, accuracy, and user experience. ### 1. Manual validation Manual validation requires obtaining a customer's voided check to manually validate account and routing information. Businesses can also directly contact their customer's bank to validate this information. **Timeline:** Up to 6 days\ **Experience:** Most labor-intensive and high-friction method ### 2. Microdeposits Microdeposits involve two steps: 1. After a customer provides their account and routing numbers, businesses make one or two very small deposits (typically less than \$0.05) into a customer's account 2. The customer confirms the exact amount deposited to validate their account **Timeline:** A few hours up to 2-3 days\ **Experience:** Creates friction that can lead to customer drop-off ### 3. Pre-notes Pre-notification transactions are essentially the same as microdeposits, but they don't require the customer to confirm the amount deposited. Instead of sending a microdeposit, the business sends a \$0 ACH transaction to validate the account information. **Timeline:** 2-3 days\ **Limitation:** Customers can't initiate payments during this time ### 4. Data API solutions Automated verification systems can verify account status for approximately 90% of domestic consumer accounts without requiring end-user interaction. **Timeline:** Seconds\ **Experience:** No customer interaction needed ### 5. Open-banking APIs Open-banking APIs use application program interfaces (APIs) and secure bank connections to retrieve account and routing numbers directly from the accounts being validated. Users select their financial institutions from a list, enter their username and password, and are quickly connected. **Timeline:** Often just a few seconds\ **Advantage:** Only verification method that uses bank account username and password rather than account and routing numbers ## Comparison of validation methods | Method | Response Time | Customer Experience | Ownership Verification | Status Validation | Balance Info | Customer Interaction | Cost | | - | - | - | - | - | - | - | - | | Data API | Seconds | Excellent | Yes (80%+) | Yes | No | Not needed | Moderate | | Open Banking | Seconds | Very good | Yes | Yes | Yes | Required | High | | Micro-Deposits | 2-3 Days | Poor | Account Control Only | Yes | No | Required | Moderate | | ACH Pre-note | 2-3 Days | Poor | No | Yes | No | Not needed | Low | | Manual | Variable | Poor | No | No | No | Required | High | Use a credential-based authentication method wherever possible. Consider implementing a frictionless solution as a fallback for when your primary connectivity provider cannot connect to a user's bank. ## The future of online account-to-account payments In 2020, there was tremendous growth in the volume of internet-initiated ACH transfers, as well as ACH transfers overall. Nacha's new rule may require many businesses to implement changes to their onboarding flows, but those changes represent an opportunity for growth. ### Benefits of compliance With the uptick in ACH use, businesses that use this rule change as a chance to implement better customer onboarding and payments experiences should expect to see: * More paying customers * Faster onboarding * Enhanced fraud mitigation * Better conversion rates * More funded accounts With instant verification, onboarding customers to ACH will be more reliable, safe, and faster than ever—all while going above and beyond to meet the requirements for Nacha's new account validation rule. # ACH payment authorization guide Source: https://docs.straddle.com/help/Payment-Compliance/ach-auth A comprehensive guide to obtaining proper ACH payment authorization from customers to avoid chargebacks, disputes, and Nacha compliance issues. > Comprehensive guide to obtaining proper ACH authorization to avoid chargebacks, disputes, and compliance issues **TL;DR**: Proper authorization is the key to avoiding chargebacks. Follow Nacha rules for written, signed authorization with specific transaction details, maintain records for 2 years, and provide clear revocation methods. ## Authorization requirements Obtaining proper authorization for ACH transactions is the most important step you can take to protect against disputes, [return fees](/help/nacha-rules/ach-return), and reversed transactions. According to [Nacha](/help/ACH101/what-is-nacha) (the organization that oversees the [Automated Clearing House network](/help/ACH101/ach-basics)), there are only **three reasons** people can dispute ACH charges: 1. **Never authorized** - The transaction was never authorized by the account holder or the authorization was revoked 2. **Wrong timing** - The transaction was processed on a date earlier than authorized 3. **Wrong amount** - The transaction is for an amount different than authorized Disputing an ACH charge requires the account holder to provide written notice to the bank that one of these three conditions exists. This is significantly different from credit card transactions where customers can reverse charges by claiming dissatisfaction with products or services. ## Required information to collect You must collect and maintain the following information from customers for **two years** after the last payment: ### Clear, legible consent Your authorization page or consent checkbox must plainly state that you're obtaining consent to debit the customer's bank account. Include express language such as: > I authorize \[your company] to electronically debit my account and, if necessary, electronically credit my account to correct erroneous debits. ### Transaction specific details * Date and time of transaction * Debiting account information (bank name and last 4 digits minimum) * Item purchased * IP address and corresponding details (email/phone) * Payment frequency for recurring transactions ### Client/account information * Name on account and shipping information * Identity verification controls * Any additional authentication measures ### Transaction history * Prior transaction history (especially for recurring payments) * IP information and login details * Previous purchase records ### Receipt of transaction * Prompt customers to print and retain authorization copies * Send email receipts for processed transactions * Maintain digital or paper copies ### Process for revocation Your authorization flow must provide customers with a clear method to revoke authorization. Include a telephone number and/or email address on both the authorization page and confirmation receipts. ## SEC codes An [SEC code](/help/Payment-Compliance/sec-codes) is a three-letter code that describes how a payment was authorized by the consumer or business. | SEC Code | Direction | Requirement | | - | - | - | | **PPD** (Corporate to Consumer) | Credits | Authorization required. Oral or non-written means (voided check) accepted | | **PPD** (Corporate to Consumer) | Debits | Authorization required. Written, signed, or similarly authenticated | | **CCD** (Corporate to Corporate) | Debits/Credits | Agreement required for transfers between companies; written authorization implied | | **WEB** (Corporate to Consumer) | Debits | Similarly authenticated authorization required due to Internet nature | | **WEB** (Consumer to Consumer) | Credits | No authorization required | | **POS** (Point-of-Sale) | Debit/Credit | Written and signed or similarly authenticated | If you want to ensure compliance without becoming an ACH rules expert, focus on the practical examples and requirements outlined in this guide. ## WEB debit entries (Internet transactions) For Internet-initiated transactions ([WEB entries](/help/Payment-Compliance/sec-codes)), additional requirements apply. See also our guide on [Internet vs Contract authorization](/help/Payment-Compliance/consent-types). ### Authorization requirements * **Written authorization** - Must be readable on screen or visual display * **Similarly authenticated** - Digital signatures, codes, shared secrets, PINs, or biometrics * **Simultaneous authentication** - Authorization and authentication should occur at the same time Only the receiver may authorize WEB transactions - not third-party service providers on their behalf. ### Authentication methods The authentication method must: * Identify the receiver * Demonstrate the receiver's consent to the authorization * Be sufficiently linked to the authorization process Examples include: * Digital signatures * Secure codes or PINs * Shared secrets * Biometric verification ### Record keeping You must maintain: * Copy of the authorization language * Record of the authentication process * Transaction details including receiver information * Date/timestamp of login and authorization **Example**: Provide a screenshot of authorization language plus date/timestamp of receiver login and authentication process that evidenced both identity and consent. ## Standing authorizations [Standing authorizations](/help/Payment-Compliance/standing-auth) allow consumers to authorize future debits that they initiate through subsequent actions. ### Requirements * **Advance authorization** for one or more future entries * **Clear specification** of actions receivers can take to initiate payments * **Receiver's affirmative action** required for each transaction ### Examples of standing authorizations * **Bill payment** - Intermittent payments via phone, online, mobile app, or text * **E-wallet services** - Future debits for personal financial management * **Virtual assistants** - E-commerce payments via voice commands * **Account transfers** - Investment account funding based on activity ### Record retention Maintain for **two years**: * Original or copy of each standing authorization * Proof that receiver initiated each payment according to authorization terms ## General authorization requirements (PPD entries) For Prearranged Payment and Deposit entries: ### Debit entries must * Be in writing * Be readily identifiable as ACH authorization * Have clear, understandable terms * Meet minimum authorization requirements * Be signed or similarly authenticated by consumer ### Credit entries Authorization may be obtained: * In writing * Orally * By other non-written means You must provide receivers a copy of authorization for all debit entries and retain records for two years from termination or revocation. ## Similarly authenticated standard As an alternative to written signatures, consumers may authenticate authorizations through: ### Telephone authentication * Minimum four-digit PIN codes * PIN printed on written authorization (for new relationships) * Audio recording of verbal codes * Record of VRU keystrokes ### Best practices * Ensure PIN is in consumer's possession during call * Be cautious with outbound calls to new customers * Comply with FTC Telemarketing Sales Rule * Make authorization language clear and conspicuous Retain records of authentication codes, including audio recordings for verbal codes and keystroke records for VRU entries. ## Notice requirements ### Amount changes If debit amount differs from previous entry or preauthorized amount: * Send written notification at least **10 calendar days** prior * Include amount and scheduled debit date * No notice required if within agreed-upon range ### Date changes If scheduled debit date changes: * Send written notification at least **7 calendar days** prior * Weekend/holiday variations don't require notice ## Compliance summary **Key compliance checklist:** * Obtain proper written, signed authorization * Collect all required transaction details * Maintain records for 2 years minimum * Provide clear revocation process * Send required notices for changes * Use appropriate SEC codes * Implement proper authentication for Internet transactions Following these authorization requirements protects against disputes, ensures Nacha compliance, and reduces the risk of returned transactions and associated fees. ## ACH authorization language This page provides sample authorization language for ACH debits and credits that can be incorporated into your terms of service. By agreeing to these Terms, you authorize **\[\[Business Name]]** ("***\[\[Company]]***") to electronically debit and credit your designated deposit account at your designated depository financial institution (your "Bank Account") via ACH and, if ever applicable, to correct erroneous debits and credits via ACH for: Choose and use only one of the following authorization types: * **Single (one-time) entry** for *\[\[date and amount]]* * **Recurring entries** (that recur at substantially regular intervals without my affirmative action to initiate future entries) *\[\[interval and amount]]* * **Subsequent entries** (initiated under the terms of my standing authorization) that require my affirmative action to initiate those future entries You also acknowledge that the amount and frequency of the foregoing debits and credits may vary and that you waive your right to receive prior notice of the amount and date of each debit and credit. ### Electronic authorization terms You acknowledge that the electronic authorization contained in this ACH Authorization represents your written authorization for ACH transactions as provided herein and will remain in full force and effect until you notify **\[\[Company]]** that you wish to revoke this authorization by emailing **\[\[support email address]]**. You must notify ***\[\[Company]]*** at least 14 Business Days before the scheduled debit date of any ACH transaction from your Bank Account in order to cancel this authorization. If we do not receive notice at least 14 Business Days before the scheduled debit date, we may attempt, in our sole discretion, to cancel the debit transaction. However, we assume no responsibility for our failure to do so. ### Account suspension upon authorization withdrawal If you withdraw your electronic authorization contained in this ACH Authorization, we will suspend or close your ***\[\[Company]]*** account, and you will no longer be able to use your ***\[\[Company]]*** account or the Services, except as otherwise expressly provided in our terms of service (*\[\[link to terms of service]]*). Withdrawal of your electronic authorization contained in this ACH Authorization will not apply to transactions performed before the withdrawal of your authorization becomes effective. ### Representations and warranties In addition to any of your other representations and warranties in this ACH Authorization, you represent that: 1. Your browser is equipped with at least 128-bit security encryption 2. You are capable of printing, storing, or otherwise saving a copy of this electronic authorization for your records 3. The ACH transactions you hereby authorize comply with applicable law Ensure all placeholder variables (marked with double brackets) are properly filled in before implementing this authorization language in your terms of service. ## Web payment forms For custom payment forms that directly integrate with the Straddle API, you must display the authorization terms on your payment page or have the buyer "click to consent" before confirming the payment. ## Recommended authorization We recommend that you use the following consent text for your custom payment form or in the application/website user agreement. This text must include the customer's name, bank account information, and the date. > By clicking \[accept], you authorize Widgets Inc to debit the bank account specified above for any amount owed for charges arising from your use of Widgets Inc's services and/or purchase of products from Widgets Inc, pursuant to Widgets Inc's website and terms, until this authorization is revoked. You may amend or cancel this authorization at any time by providing notice to Widgets Inc with 30 (thirty) days notice. Replace "Widgets Inc" with your actual company name in the authorization text. ### Future payments If you plan to use the customer's bank account for future payments, also include this additional text: > If you use Widgets Inc's services or purchase additional products periodically pursuant to Widgets Inc's terms, you authorize Widgets Inc to debit your bank account periodically. Payments that fall outside of the regular debits authorized above will only be debited after your authorization is obtained. Make sure the authorization text is clearly visible to customers before they complete their payment. Consider using checkboxes or prominent buttons to ensure explicit consent. ## Customer consent requirements Regardless of the end-user experience, your application must capture customer consent in a reproducible fashion. This consent will be used to protect you from customer disputes. ## ACH authorization form component For developers building custom payment flows, we provide a pre-built React component that handles ACH authorization display and consent collection. This component ensures compliance with Nacha requirements while providing a clean, professional user interface. ### ACHAuthorizationForm component A complete React component that displays ACH authorization terms with customizable business information and built-in consent handling. **Key features** * Compliant authorization language following Nacha guidelines * Customizable business information (company name, support email, etc.) * Professional styling with proper typography and spacing * Responsive design for all device sizes * Built-in consent tracking and validation **Props** | Prop | Description | | - | - | | `businessName` | Your company's legal business name | | `companyName` | Display name for your company | | `supportEmail` | Customer support email address | | `onConsentChange` | Callback function when consent status changes | | `className` | Optional CSS classes for styling customization | **Usage example** ```tsx theme={null} import { ACHAuthorizationForm } from './components/ACHAuthorizationForm' function PaymentPage() { const [hasConsent, setHasConsent] = useState(false) return (
) } ``` **Implementation notes** * Component automatically handles consent state management * Includes proper ARIA labels for accessibility * Displays authorization terms in a scrollable, readable format * Provides clear visual indication of consent requirement * Maintains authorization timestamp for compliance records This component is designed to be drop-in ready for most payment flows while ensuring full compliance with ACH authorization requirements. Customize the styling and business information to match your brand. **Best Practice**: Always validate that consent has been obtained before processing any ACH transactions. The component's `onConsentChange` callback makes this easy to implement in your payment flow. ## Sending notification emails You can send custom email notifications to customers to satisfy Nacha requirements. In the email, include the following information: * Authorization date * Amount * Account holder name * Financial institution * Routing number * Last four digits of the account number The following is a sample auth confirmation email that you can send. ### Sample: Direct debit authorization confirmation Thank you for signing up for direct debits from Widgets Inc. You have authorized Widgets Inc to debit the bank account specified above for any amount owed for charges arising from your use of Widgets Inc's services and/or purchase of products from Widgets Inc, pursuant to Widgets Inc's website and terms, until this authorization is revoked. **Modifying your authorization** You may amend or cancel this authorization at any time by providing notice to Widgets Inc with 30 (thirty) days notice. **Transaction details** | Field | Details | | :- | :- | | **Consent Date** | June 28, 2021 | | **Payment Date** | June 16, 2023 | | **Amount** | \$50.00 | **Account information** *Account holder:* Bob Loblaw *Financial institution details:* * **Bank:** Chase Bank * **Routing Number:** 021000021 * **Account Number:** \*\*\*\*6789 Account numbers are partially masked for security purposes. Only the last four digits are displayed. Keep this confirmation for your records. You can modify or cancel your direct debit authorization at any time with proper notice. ## CCD authorization requirements As with all ACH transactions, the Originator of a [CCD entry](/help/Payment-Compliance/sec-codes) must receive the Receiver's authorization to debit or credit the Receiver's account. The Nacha Operating Rules do not require the CCD/CTX authorization to be in a specific form. However, the rules require the Originator and Receiver to have an agreement that binds the Receiver to the Rules. ### Trading partner agreements This trading partner agreement should contain the authorization requirements and procedures as determined by the parties. The companies negotiate the terms based on their specific business needs and requirements. Nacha isn't very helpful with specifics here due to the varied nature of B2B (CCD) transactions. ## Best practices recommendation Our recommendation would be to follow best practices outlined in this guide while also including specific language to the following effect: Both parties agree to be bound by [Nacha Operating Rules](/help/nacha-rules/ach-rules) as they pertain to all ACH transactions initiated by **\[YOUR COMPANY Full Entity Legal Name]** that credit or debit the **\[YOUR CUSTOMER Full Entity Legal Name]** bank account and acknowledge that the origination of ACH transactions to the listed account must comply with provisions of U.S. law. Replace the placeholder text **\[YOUR COMPANY Full Entity Legal Name]** and **\[YOUR CUSTOMER Full Entity Legal Name]** with the actual legal entity names when implementing this clause. This clause establishes legal binding obligations under Nacha Operating Rules and U.S. law for ACH transactions between the specified parties. ### Key components * **Nacha Operating Rules compliance** - Both parties must adhere to established ACH network rules * **Transaction scope** - Applies to all ACH credits and debits to the specified account * **Legal compliance** - Must comply with applicable U.S. legal provisions * **Entity identification** - Requires full legal entity names for both parties # Understanding consent methods: Internet vs. Signed Source: https://docs.straddle.com/help/Payment-Compliance/consent-types Compare internet (WEB) and signed (PPD) consent methods for ACH payments to choose the authorization type that fits your customer flow and Nacha rules. **TL;DR:** Select "**internet**" for electronic consent obtained via web or mobile apps. Select "**signed**" for signed agreements, including e-signatures like DocuSign, obtained *before* initiating payments. \ **Note:** If you're a B2B company that holds signed contracts, even though you may submit payments via the web portal or payment app, you would select "Signed". During the Straddle application process, you're asked to select how you obtain [authorization](/help/Payment-Compliance/ach-auth) for electronic payments from your customers. Selecting the correct method is crucial for payment compliance per regulators like [Nacha](/help/ACH101/what-is-nacha). The two options are "internet" and "signed." ## Authorization use cases | Authorization Use Case | Consent Method to Select | | - | - | | Business to Business contract | `signed` | | Business to Consumer contract | `signed` | | Web Authorization via payment portal or mobile application | `internet` | You can select both `signed` and `internet` options if your business uses multiple consent methods. ## Internet consent Select this option if you collect electronic consent through a web portal or mobile application. ### Examples * Customers agree to terms by clicking a "checkbox" agreeing to electronic consent * Users authorize payments within your mobile app * Consent is given through an online form submission ### Key considerations * Typically used for digital-first businesses * Suitable for recurring payments set up online * Must comply with electronic consent regulations and [WEB SEC code](/help/Payment-Compliance/sec-codes) requirements ## Signed consent Select this option if you obtain a signed agreement from your customer *before* initiating a payment; *this includes electronic signatures*. ### Examples * B2B or B2C contracts signed in person or E-signature services like DocuSign, Adobe sign, etc (relates to [PPD or CCD SEC codes](/help/Payment-Compliance/sec-codes)) * Emailed agreements returned with a digital signature ### Key considerations * Often used for high-value or long-term agreements * Use this option for business-to-business transactions (see [CCD entries](/help/Payment-Compliance/sec-codes) for B2B requirements) # Cannabis Related Business Due Diligence Source: https://docs.straddle.com/help/Payment-Compliance/crb-dd Requirements and enhanced due diligence (EDD) procedures for onboarding cannabis-related businesses (CRBs) on the Straddle ACH payments platform. This guide outlines the comprehensive documentation requirements for onboarding Cannabis Related Businesses (CRB) that require enhanced due diligence procedures. **Required Documents Summary** * Business Operating Agreement * Articles of Organization * State cannabis licenses (and City, if applicable) * County/municipal cannabis permits * Certificate of Use/Occupancy * Last 3 months of bank statements * Annual statement * KYC information for **everyone** owning 10% or more of the business * Government issued IDs * Full SSN * EIN documentation * Organization chart showing business ownership structure, including **all Beneficial Owners** * DBA/Fictitious Business Name filing (if you operate under a different name) ## Document requirements ### Business documents These documents prove your business is legally established and show us how your company is structured. Think of them as your business's birth certificate and instruction manual. They're fundamental to proving you're a legitimate operation. * Your Operating Agreement * Original Articles of Organization * DBA/Fictitious Name (if applicable) ### Licenses and permits Your licenses and permits show you're operating legally in your jurisdiction. We need to verify all your authorizations are current and valid. The Certificate of Use of Occupancy confirms your business location is properly zoned and safe for cannabis operations. * State Cannabis License * City Cannabis License (if your city requires one) * Any additional county or municipal cannabis permits * Certificate of Use of Occupancy ### Financial records Recent bank statements help us understand your typical business activity and cash flow. The annual statement gives us a broader view of your business's financial health. Your EIN documentation confirms your federal tax registration status. * Last 3 months of bank statements * One annual bank statement * EIN documentation ### Ownership information Banking regulations require us to know and verify the identity of all major business owners. This helps prevent financial crimes and ensures transparency in the cannabis industry. * Government ID (driver's license or passport) for all owners with 10% or more ownership * Organization chart showing your business structure * Complete our KYC verification process through our Weave program ## What to expect after submission Our team reviews your documents within 1-7 business days and reaches out if we need any clarification or additional information. Sponsor bank approval can take approximately 14 days, and you receive an approval response once bank approval is confirmed. ## Keeping your account in good standing To maintain your relationship with Straddle: * Keep all licenses and permits current * Notify us of any ownership changes * Update us if you change business locations * Maintain accurate financial records Remember, maintaining current documentation helps ensure uninterrupted services. We'll send reminders when it's time to update your information, but feel free to contact us anytime with questions about your account or documentation requirements. # ACH data security and Nacha audits Source: https://docs.straddle.com/help/Payment-Compliance/data-security Meet Nacha's data security rules and annual ACH audit requirements with practical guidance on encryption, access controls, and ongoing compliance. Effective 2021 the National Automated Clearing House Association also referred to as NACHA is requiring an annual audit to ensure the security of financial information. This audit focuses on web debit transaction origination and customer bank information security, specifically for ACH (non-card transactions). ## What are the requirements? Complete an annual audit conducted on your behalf, to ensure the financial information is protected by security practices and procedures. Security practices at a minimum should include an adequate level of: * **Physical security** to protect against theft, tampering, or damage * **Personnel and access controls** to protect against unauthorized access and use * **Network security** to ensure capture, storage, and distribution The document attached below outlines the minimum requirements to be NACHA compliant. ## What action is required of me? To complete this audit and provide the necessary information to Straddle, use the web form here: [Click me!](#) **Don't Rush** This is a once-per-year kind of thing. While it's important to do it right, you have time to get there. If you completed the Web Debit Security Audit previously, you must review your responses and visit this form to certify that no changes have been made to your organization's policies and procedures that would affect compliance with Nacha's Operating Rules and Guidelines. ## Who in our organization would be best equipped to answer the questions in this audit? Someone within your IT Department or your IT Vendor would be a great resource in answering the questions in the Web Debit Security Audit. ## What if we do not have these policies or processes in place? If you answer no to any questions in the audit or are unable to supply the document name when needed, your organization will be considered non-compliant. In this instance, Straddle needs a remediation plan and timeline from your organization. Additionally, you can refer to the Federal Communication Commission (FCC) website for cybersecurity for small businesses. The Cybersecurity Hub was designed for businesses that lack the resources to hire a dedicated staff member to protect their business from cyber threats. FCC Cybersecurity for Small Businesses includes links to free and low-cost security tools (e.g. a Cybersecurity Tip Sheet, and Small Biz Cyber Planner) to assist small businesses to create customized cybersecurity plans. ## What if no one in my organization can answer the audit questions? If you are unable to locate anyone to complete the audit questions, contact Straddle compliance via email at [compliance@straddle.com](mailto:compliance@straddle.com) for additional support. A vendor may be necessary to conduct the audit. Straddle does not endorse any vendor or company; however, Cyber Research Databank provides a resource page to find the latest trends of US Data Security companies and offers a unique and easy to navigate database with more than 5000 US Data Security vendors/companies. ## What is Nacha? Nacha was originally NACHA, an acronym for National Automated Clearing House Association. Though the acronym is no longer in official use (they go by 'Nacha' instead), it shows where the organization came from and the role they fill in the ACH ecosystem. Back in the early 1970s, regional banking associations across the US joined forces to standardize processes around the development of "automated" clearing house solutions—the digital replacements for physical clearinghouses where paper checks were once exchanged. By 1974, the American Bankers Association had centralized all of those regional groups under a national sub-division that they named NACHA. An independent organization since 1985, Nacha is effectively a non-profit consortium tasked with: * Translating federal legislation and executive rules into clear guidance for member banks and ACH network participants * Enforcing those rules for all 10,000+ member banks and network participants * Driving development and adoption of the ACH system * Acting as a trade organization (e.g., education, advocacy, roundtables, etc.) ## What's the difference between Nacha and ACH? The Automated Clearing House (ACH) network is the American interbank funds-transferring system run by two national operators: The Clearing House and FedACH. Nacha is the governing body that oversees the ACH network. It ensures that member banks are aware of and compliant with related federal legislation, along with promoting development and education around ACH. As for the operators that run the ACH network: **The Clearing House** (also referred to as TCH or PayCo) is itself another banking consortium, with a much smaller subset of the major US banks (currently 24). They run a system called Electronic Payments Network (EPN), which is the ACH operator for all private banks in the ACH network. **FedACH** is part of the Federal Reserve system, performing the same function as EPN, for government accounts and entities, rather than private ones. When an ACH transaction involves both a government account and a private account, the two operators work together to pass the corresponding data between themselves accordingly. Nacha translates mandates from the US government into actionable rules and standards for The Clearing House and FedACH, which then operate their respective parts of the ACH network in accordance with Nacha's guidance. Nacha also mediates between members and acts as an advocate for the ACH ecosystem to the larger financial industry. ## What is the specific Nacha security audit guidance for WEB debits? The minimum elements required by an annual data security audit are outlined by Section V – Standard Entry Class Codes, Chapter 48 Internet Initiated/Mobile Entries in the 2020 NACHA Operating Guidelines: ### Annual data security audits Data loss or compromise not only hurts the Receiver, but can also damage a business's reputation. Receiver trust is a key factor in building loyalty. It is in the Originator's best interest to develop and deploy practices that protect the integrity of Receiver information and the transaction, and to ensure that these practices are audited for their effectiveness. The Nacha Operating Rules for debit WEB transactions require Originators to conduct an annual data security audit to ensure that Receivers' financial information is protected by security practices and procedures that ensure the financial information the Originator obtains from Receivers is protected by commercially reasonable security practices that include adequate levels of: * Physical security to protect against theft, tampering, or damage * Administrative, technical, and physical access controls to protect against unauthorized access and use * Network security to ensure secure capture, transmission, storage, distribution and destruction of financial information While the Nacha Operating Rules only require Originators of debit WEB Entries to conduct an audit of their security practices and procedures once a year, many companies are now opting to audit these practices bi-annually or even quarterly due to the rapid change of technology and security risks. It is therefore highly recommended that Originators of debit WEB entries conduct more frequent audits. This audit requirement can be met in several ways. It can be a component of a comprehensive internal or external audit, or it can be an independent audit that uses a commercially reasonable generally accepted security compliance program. An Originator that is already conducting an audit of these practices and procedures for another area of its business is not required to have two separate audits. However, the audit should address adequate levels of data security for the Originator's ACH operations. The following sections detail the minimum components that need to be audited in order to be in compliance with the audit requirement. (NOTE: In any case where these key components are not specifically required under the Nacha Operating Rules, all are recommended by Nacha as sound business practices.) ### Physical security to protect against theft, tampering or damage * Critical network, server, and telecommunications equipment should be placed in physically secure locations that permit access only to authorized personnel * Firewalls must be fully deployed with secured processes for administering those firewalls * Firewalls must protect websites from inappropriate and unauthorized access * Disaster recovery plans must be developed and reviewed periodically ### Personnel and access controls to protect against unauthorized access and use * A formal set of security policies and procedures must be developed that clearly outline the corporate rules governing access to sensitive financial data * Hiring procedures should be developed that will, at a minimum, verify application information and check references on new employees that will have access to Receiver financial information * Relevant employees must be educated on information security and company practices and their individual responsibilities * Access controls should be in place to ensure adequate administrative, technical, and physical controls: * Limit employee access to secure areas and to documents/files that contain Receiver financial information * Ensure that terminated employees have no access to secure information and areas * Permit visitors only when absolutely necessary to these areas and information and ensure they are accompanied by an employee at all times * Authenticate all access to any database containing sensitive ACH information such as financial information (e.g., passwords or passphrase, multifactor authentication such as token devices, smart cards, biometrics, or public keys) * Implement key-management procedures to require split knowledge for dual control of keys (e.g., requiring two or three people (or processes or procedures) to cooperate in gaining authorized access to a system resource (data, files, devices) – a separation of duties) * Establish policies and procedures to monitor and audit all user activity for personnel with access to Receiver information in order to detect exceptions ### Network security to ensure secure capture, transmission, storage, distribution, and destruction * Install and maintain a firewall configuration to protect all Receiver financial information, including but not limited to the company network and databases, and portable electronic devices (e.g., employee laptops, smartphones, etc.) * Install and update anti-virus software on a regular basis * Ensure all system components have the latest vendor-supplied security patches installed * Change vendor-supplied defaults before installing a system on the network * Minimize retention and/or storage of all Receiver financial information * Develop a data retention and disposal policy and schedule to include a process (manual or automatic), to remove, at least on a quarterly basis, any unnecessary Receiver financial information. Monitor these retention schedules regularly * Receiver financial information should only be stored permanently if it is required by law, regulation, rule, or a governing organization * Limit distribution of Receiver financial and personal information and implement procedures and policies to govern the distribution of sensitive financial information * Review data distribution policies and procedures periodically * Encrypt Receiver data and financial information at all points in the transaction lifecycle from transmission to storage via a secure, electronic means that provides a commercially reasonable level of security compliant with current, applicable regulatory guidelines * Render account numbers used in the origination and transmission of ACH transactions unreadable when stored electronically * Regularly test security systems and processes (e.g., vulnerability scans, external and internal penetration testing, intrusion detection, file integrity monitoring) It is important to note that for transactions that involve some use of the Internet but are not defined as WEB transactions, Originators must incorporate the security and risk management principles of the WEB rules, as applicable. For example the Originator is required to authenticate the Receiver and conduct a data security audit to ensure the Receiver's data is stored securely. # ACH SEC codes reference Source: https://docs.straddle.com/help/Payment-Compliance/sec-codes Reference for ACH Standard Entry Class (SEC) codes, including WEB, PPD, CCD, and TEL, with use cases and Nacha authorization requirements for each code. ## What are SEC codes? An SEC code is a three-letter code that describes how a payment was authorized by the consumer or business receiving an [ACH transaction](/help/ACH101/ach-basics). ## How SEC codes work in practice The Originator is responsible for including the correct SEC code in the ACH payment when originating a file. SEC codes are attached to the ACH payment request as part of the NACHA file format. The Originator must also have proper [authorization](/help/Payment-Compliance/ach-auth) from the Receiver. **The nature of this authorization depends on the SEC code and whether funds are being [debited](/help/ACH101/ach-debit) or [credited](/help/ACH101/ach-credit)**. Most [ACH debits](/help/ACH101/ach-debit) (Straddle [**charges**](/api-reference/charges/create)) require written or electronic authorization from the recipient, while most [ACH credits](/help/ACH101/ach-credit) (Straddle [**payouts**](/api-reference/payouts/create)) do not. ### Phone authorization requirements Debits authorized by phone call need to use the SEC code **TEL** (see full [SEC Code authorization rules](/help/nacha-rules/ach-rules)) and require the company originating the payment to: * Maintain a recording of the customer's verbal authorization, **or** * Follow up with the customer for written confirmation of the authorization before initiating the payment Including the incorrect SEC code could result in an ACH Return. The Originator is responsible for any return fees and must resubmit the payment with the correct code. ## Common SEC codes and their requirements | SEC Code | Description | Direction | Authorization Requirement | | - | - | - | - | | **PPD** | Prearranged Payment & Deposit (Corporate to Consumer) | Credits | Authorization required. Oral or non-written means (such as voided check) accepted. | | **PPD** | Prearranged Payment & Deposit (Corporate to Consumer) | Debits | Authorization required. Written, signed, or similarly authenticated. | | **CCD** | Corporate Credit or Debit (Corporate to Corporate) | Debits/Credits | Agreement required for transfers between companies; written authorization implied. | | **WEB** | Internet-Initiated/Mobile Entry (Corporate to Consumer) | Debits | Similarly authenticated authorization required due to the nature of the Internet. | | **WEB** | Internet-Initiated/Mobile Entry (Consumer to Consumer) | Credits | No authorization required. | | **POS** | Point-of-Sale | Debit/Credit | Written and signed or similarly authenticated. | ## Why proper authorization matters Obtaining the proper [authorization](/help/Payment-Compliance/ach-auth) for your ACH transaction is the most important step you can take to ensure compliance with [network rules](/help/nacha-rules/ach-rules) and protect yourself against disputes, [return fees](/help/nacha-rules/ach-return), and reversed transactions. # Standing authorizations for recurring ACH Source: https://docs.straddle.com/help/Payment-Compliance/standing-auth Understand Nacha's standards for standing authorizations, the advance consent consumers give for future ACH debits at varying amounts and intervals. ## Standing authorizations The Standing Authorizations Rule (the Rule) established standards for a standing [authorization](/help/Payment-Compliance/ach-auth) as an advance authorization by a consumer of future debits at various intervals. Under a Standing Authorization, future [debits](/help/ACH101/ach-debit) are initiated by the consumer through further actions. The Rule allows for Originators to obtain Standing Authorizations in writing or orally. The Rule also defines Subsequent Entries, which are individual payments initiated based on a Standing Authorization. Subsequent Entries may be initiated in any manner identified in the Standing Authorization. The Rule allows Originators some flexibility in the use of consumer [Standard Entry Class (SEC) Codes](/help/Payment-Compliance/sec-codes) for individual Subsequent Entries. Originators may use the TEL or WEB SEC Codes for Subsequent Entries when initiated by either a telephone call or via the Internet/wireless network, respectively, regardless of how the Standing Authorization was obtained. In these cases, the Originator does not need to meet the authorization requirements of TEL or WEB, but does need to meet the risk management and security requirements associated with those SEC Codes. In addition, the Rule allows for optional formatting so an Originator may, at its discretion, identify an entry as having been originated under the terms of a Recurring, Single-Entry or Standing Authorization. The standard code values will be "R" for Recurring, "S" for Single-Entry, and "ST" for Standing Authorization. An Originator may choose to include these values in the Payment Type Code Field of a TEL or WEB entry or the Discretionary Data Field of a PPD entry. In order to accommodate this option, the Rule removed the existing requirement that TEL and WEB entries must be identified as either Recurring or Single Entries, and designates the Payment Type Code as an optional field. ## Use of WEB Standard Entry Class code for subsequent entries At its discretion, an Originator may identify a Subsequent Entry as a debit [WEB Entry](/help/Payment-Compliance/sec-codes) if the Receiver's affirmative action for the initiation of the Subsequent Entry is communicated by the Receiver to the Originator via the Internet or a Wireless Network, regardless of the manner in which the Standing Authorization was obtained. The requirements of Subsection 2.5.17.6 (Verification of Routing Numbers) apply to a Subsequent Entry that is a debit WEB Entry only if the routing number was communicated via (a) an Oral Authorization via the telephone, or (b) the Internet or a Wireless Network, regardless of whether the routing number was communicated in conjunction with the Standing Authorization or Subsequent Entry. ## Standing authorization requirements A Standing Authorization is an advance [authorization](/help/Payment-Compliance/ach-auth) obtained from a Receiver for one or more future entries (referred to as subsequent entries) that require the Receiver's affirmative action to initiate. An Originator of a standing authorization must meet the minimum standards for a consumer [debit authorization](/help/ACH101/ach-debit) identified above, but it may do so through a combination of the standing authorization and the Receiver's affirmative action to initiate each subsequent entry. As part of the terms of a standing authorization, the Originator must clearly specify the action(s) that the Receiver can take to initiate a subsequent entry. These actions can include, but are not limited to, a telephone call, an internet interaction, or a text message. Examples of standing authorizations include, among others: * Bill payment - A standing authorization could allow a consumer to initiate payments on a credit card account intermittently and via various channels (phone, online, mobile app, text, virtual assistant technology, etc.) * E-wallet/personal financial management - A consumer could provide a standing authorization for future debits related to using an e-wallet or other personal financial management service * Personal or home virtual assistants - A standing authorization could be used in conjunction with services and apps that allow future e-commerce and payments to be initiated via virtual voice assistant or similar functionality * Account transfers - A consumer could provide a standing authorization to authorize funding debits to a brokerage account based on investment activity For a standing authorization, an Originator must retain the original or a copy of each standing authorization for two years following the termination or revocation of the authorization. The Originator must also retain proof that the Receiver affirmatively initiated each payment in accordance with the terms of the standing authorization for two years following the Settlement Date of the entry. ## Receiver account information In any case where the Receiver's affirmative action to initiate a subsequent entry involves the communication or confirmation of any of the Receiver's banking information (such as routing number, account number, PIN, or other identification symbol) via an unsecured electronic network, the Originator must comply with ACH data security requirements. ## Standard Entry Class codes for subsequent entries In certain cases, an Originator may identify a subsequent entry using the Standard Entry Class Code appropriate either to (1) the manner in which the standing authorization was obtained from the Receiver, or (2) the manner in which the Receiver's affirmative action to initiate the subsequent entry was communicated to the Originator. However, the Rules do not allow an Originator that obtains the Receiver's standing authorization using the WEB or TEL Standard Entry Class Codes to identify subsequent entries using the PPD Standard Entry Class Code. For more information on selecting Standard Entry Class Codes, see Proper Use of Standard Entry Class Codes for Subsequent Entries later in this chapter. See Appendix H of these Guidelines for more information on the proper use of Standard Entry Class Codes for consumer entries. © 2022 Duplication of the content prohibited without permission from Nacha. # Accounts with Benefits: FBO Source: https://docs.straddle.com/help/Reference-Materials/fbo-accounts Understand For Benefit Of (FBO) accounts and how early-stage money service businesses use them to hold customer funds without a money transmitter license. Are you an early-stage Money Service Business? If so, you're probably aware that the US licensing system is insane and it could take several years and millions of dollars just to get regulatory coverage for your service. Unless... **TL;DR**: An FBO account, or a For Benefit Of account, is a type of custodial account that allows a company to manage funds on behalf of, or "for the benefit of," one or more of their users without assuming legal ownership of that account. Two key potential benefits of an FBO are sub-accounts with FDIC insurance and regulatory cover. If the FBO is in the bank's EIN, this structure can be helpful for businesses seeking to avoid certain kinds of regulatory categories, for instance, the possibility of the business being directly regulated as a "money transmitter." ## What is an FBO account? Ownership of an FBO can either be attributed to the bank's EIN (tax ID) or the name of the company. If the FBO is in the bank's EIN, this structure can be helpful for businesses seeking to avoid certain kinds of regulatory categories, for instance, the possibility of the business being directly regulated as a "money transmitter." Because chartered banks are exempt from money transmission licensing requirements, many fintechs leverage the FBO account structure where the banks technically have custody of the assets; allowing the fintech to legally provide services across the United States. ## Why would my fintech need an FBO account? Well, that depends! Could your business be considered a money transmitter? Under federal law, a money transmitter is defined as someone who receives money from one person and transmits it to another. The definition is purposely circular to give regulators wide latitude to label something money transmission. Typical. Money transmission can be hard to determine based on a definition alone, so let's look at examples to better understand the requirements. ### Money transmitter examples **Digital wallet companies** are generally money transmitters. They accept customer funds and move those funds to recipients, allowing customers the ability to hold funds in their wallets. Examples of registered money transmitters include PayPal and Block (formerly known as Square). **Cross-border remittance companies** like Western Union and MoneyGram also hold money transmitter licenses. They accept funds from one party and handle sending them to another, often in a different country. Money transmitters must register with federal regulators (the Financial Crimes Enforcement Network, or FinCEN) and then obtain Money Transmitter Licenses (MTLs) for each state in which they operate. This registration and licensure process is costly and time-consuming. Regulatory statutes provide many resources to help a business figure out if it is a money transmitter, but we recommend consulting legal counsel to review the applicable facts and circumstances. ## Money transmitter exceptions There are some potential paths fintechs should be aware of if they are interested in steering away from money transmission requirements. First, the definition of "money transmitter" has a few exceptions that have developed over the years, including: * Companies that only provide technology layers that money transmitters use * Payment processors that facilitate payments for goods and services through a clearance and settlement system * Companies that only accept and send funds that are integral to the sale of goods or services (for example, a P2P micro-lending platform) To steer into the technology layer path, fintechs can work with bank partners to set up "for the benefit of" (FBO) accounts. These are custodial accounts that let a company manage funds on behalf of others without technically having legal ownership of the account. By using a properly constructed FBO account arrangement with a regulated bank, a business can avoid the need to individually register and obtain licenses as a money transmitter. That is because the bank already has the necessary regulatory compliance structure; banks are exempt from the need to separately register and obtain MTLs. A properly constructed FBO under a bank's EIN removes the business from having dominion or control over the user's funds. Thus, the business would not be subject to separate regulation as a money transmitter in its own right and would be able to rely on the bank's regulatory exemption. ## On-core vs FBO accounts So how are these accounts structured? | Feature | On-Core Accounts | FBO Accounts | | - | - | - | | **Account opening** | Opened directly in the end-user's name at the bank | Umbrella account that pools funds "for the benefit of" end-users | | **KYC requirements** | Bank may ask for more robust KYC information | Fintech opens FBO to issue virtual accounts | | **Account structure** | Account sits directly on the bank core | Customer has a ledger account that sits within the FBO | ### What are on-core accounts? An on-core account is an account that is opened directly in the end user's name at the bank and works just like a traditional bank account. This can be a great option for your fintech because it allows you to leverage the bank's expertise, policies and procedures. When the customer applies for an account on the fintech platform, the bank will ask the customer for pre-defined know your customer (KYC) information to verify identity, and the account will sit directly on the bank's core banking infrastructure. ### How are FBO accounts structured? An FBO account is an umbrella account that holds the aggregate deposit balances for multiple client accounts. Those funds are held at the bank for the benefit of a company's clients. No money movement in or out of that account should occur unless it is instructed by or because of an end customer's actions. These accounts are owned and controlled by the customer; the enterprise does not have any access to its customers' funds and does not technically take possession of funds at any point. An FBO account is a fiduciary account opened on a bank's core. A dedicated FBO account means the BaaS provider has opened a discrete FBO account just for that fintech at the bank. The dedicated FBO account is only for a single fintech's end customers and is not shared among multiple fintechs in a bank's portfolio. **Why is this important?** The ability to have a dedicated FBO account allows an enterprise or fintech in collaboration with its partner bank to establish risk management systems and transaction monitoring rules specifically for the risks posed by the use case of its customers. This is especially important for a regulated financial institution like your bank partner to demonstrate to its auditors that its BSA/AML program is tailored to the specific risk and use case presented by an enterprise. ## Benefits of opening an FBO account **FDIC Insurance**: Deposits held by the customer as a beneficiary to the FBO account are FDIC-insured on a pass-through basis to the same extent as if the deposits were made directly, assuming specific requirements are met. **No ownership interest**: The fintech has no ownership interest in the FBO account and has no control over the funds. The bank maintains control over the funds at all times. This is how fintechs or wallet providers can make the case that they're not engaging in money transmission activity. It's important because money transmission is regulated in all states (except Montana). The laws require fintechs to obtain licensure to take custody of funds and transmit funds to third parties. This is a complex and time consuming undertaking, unless they partner with banks. ## FBO accounts can be extremely valuable An FBO account offers a convenient alternative for companies seeking to comply with regulatory requirements in a more streamlined and efficient manner. Instead of undergoing the lengthy process of becoming a money transmitter and obtaining a Money Transmitter License, FBO account ownership is attributed to the bank's EIN (Employer Identification Number) or tax ID, which can help them custody and disburse funds in a compliant manner. ### How our bank partners help customers do it right Here's how our bank partners help customers implement FBO accounts properly: 1. **Separate FBO account** is opened or enabled by each fintech at a partner bank 2. **Transaction monitoring tools** are integrated at the top of the funnel 3. **Adequate KYC** is established for end-users and the fintech itself With these features, an FBO model is often just as valuable as on-core accounts. The nuanced feature set and framework are incredibly important for both fintechs and banks as they seek to empower innovation while mitigating risks. ## Legal references The following legal references provide the regulatory foundation for FBO account structures and money transmitter requirements: * **FIN-2019-G001**: "Application of FinCEN's Regulations to Certain Business Models Involving Convertible Virtual Currencies," (May 9, 2019) * **FIN-2013-G001**: "Application of FinCEN's Regulations to Persons Administering, Exchanging, or Using Virtual Currencies," (March 18, 2013) * **FIN-2019-A003**: "Advisory on Illicit Activity Involving Convertible Virtual Currency" (May 9, 2019) * **31 C.F.R. § 1010.100(ff)**: Money transmitter definitions and exceptions * **31 C.F.R. § 1022.380(a)(1)**: Registration requirements * **31 C.F.R. §§ 1010.100(d) and 1020**: Bank exemptions and regulations ### Key regulatory exemptions Banks and persons registered with and functionally regulated or examined by the SEC or the CFTC that engage in transactions denominated in value that substitutes for currency are exempt from MSB status but are subject to BSA regulations according to the applicable section of 31 CFR Chapter X. A person is not a money transmitter if that person only: * Provides delivery, communication, or network access services used by a money transmitter * Acts as a payment processor to facilitate purchase of goods or services through a clearance and settlement system * Operates a clearance and settlement system between BSA regulated institutions * Physically transports currency with only custodial interest * Provides prepaid access as defined in regulations * Accepts and transmits funds only integral to the sale of goods or provision of services For complete regulatory guidance and specific legal requirements, consult with qualified legal counsel familiar with FinCEN regulations and money transmitter licensing requirements. # Glossary of ACH and Straddle terms Source: https://docs.straddle.com/help/Reference-Materials/glossary A comprehensive reference of ACH, payments, identity, and Straddle platform terminology to help you understand documentation and integration concepts. # Glossary of Straddle Terms This glossary is comprehensive and detailed, designed to serve as a valuable reference during your implementation of Straddle's services. Use this as a reference guide throughout your integration process. This glossary contains technical terms specific to the Straddle platform. Bookmark this page for easy reference during development and implementation. ## A ### ACH (Automated Clearing House) An electronic network for financial transactions in the United States, used by Straddle for processing certain types of bank transfers. See our [ACH basics guide](/help/ACH101/ach-basics) for detailed information. ### Account A business entity that has entered into a contractual relationship with Straddle to utilize its services directly. Accounts can access the Straddle API Sandbox upon creation and need to complete an onboarding process for production access. ### Account Status The current state of a Straddle account, which can be one of: created, onboarding, active, rejected, or inactive. ### Account-to-Account (A2A) Payments Transactions that move money directly from one bank account to another. Straddle orchestrates A2A money movement via multiple payment rails so you don't have to worry about the complexity. ### Address Risk A component of Identity that provides a risk score for physical addresses. ### Adverse Media Screening A component of Identity that identifies individuals associated with news items related to financial crimes. ### AML (Anti-Money Laundering) Regulations and procedures that Straddle helps you comply with to prevent criminals from disguising illegally obtained funds as legitimate income. ### API (Application Programming Interface) A set of protocols and tools for building software applications, specifically referring to Straddle's API. The Straddle API allows developers to integrate payment and identity verification features into their applications. ### API Key A unique identifier used to authenticate requests to the Straddle API. API keys should be kept secure and not shared publicly. ### API Version The specific version of the Straddle API being used, which determines the available features and endpoints. ### Authentication The process of verifying the identity of a user or system making requests to the Straddle API. Straddle uses Bearer tokens for API authentication. ## B ### Balance Check A feature in Straddle's platform that verifies the available balance in a customer's account before initiating a charge. This helps prevent failed payments due to insufficient funds. ### Bank Account Verification The process of confirming that a bank account is valid and belongs to the stated owner. Straddle offers multiple methods for bank account verification, including API-based verification and open banking connections. ### Bearer Token A type of access token used for authentication in the Straddle API. ### Bridge Straddle's comprehensive suite of account connectivity endpoints that facilitate secure connections between users and their financial accounts. Bridge includes: * A drop-in open banking widget * Support for third-party tokens (e.g., Plaid, MX) * API-based bank account verification ### Bridge Token A JWT (JSON Web Token) used in the Straddle Bridge widget for secure account connectivity. Bridge tokens are generated using the `/v1/bridge/initialize` endpoint. ### Bridge Widget A drop-in user interface component provided by Straddle for easy integration of bank account connectivity features. The Bridge Widget is a hosted UI component that you can embed on your website to allow customers to connect their bank accounts to your platform. ### Business Profile A set of information about an account on the Straddle platform, including details such as legal name, business name, website, description, tax ID, address, and industry information. ## C ### Capability A specific feature or permission granted to an account on the Straddle platform. Capabilities include payment\_types, customer\_types, and consent\_types. ### Capability Request A formal request to enable a specific capability for an account on the Straddle platform. ### Charge A type of payment transaction where money is debited from a Customer. Charges correspond to [ACH debit](/help/ACH101/ach-debit) transactions and are created using the [`/v1/charges`](/api-reference/charges/create) endpoint. ### Compliance Profile A set of information in the Straddle API request when creating a Customer that triggers fully-compliant KYC validation. ### Consent Type The method by which a customer provides [authorization](/help/Payment-Compliance/ach-auth) for a transaction. Straddle supports two consent types: [internet and signed](/help/Payment-Compliance/consent-types). Related to [SEC codes](/help/Payment-Compliance/sec-codes). ### Correlation ID An optional client-generated identifier passed in the request headers to trace and debug a series of related API requests. ### Correlation Score A measure of the relationship strength between different elements of provided personally identifiable information (PII). ### Create Charge The API endpoint and process for initiating a new charge transaction. ### Create Payout The API endpoint and process for initiating a new payout transaction. ### Currency The monetary unit used for transactions on the Straddle platform. ### Customer An individual or business involved in a payment transaction with your business. All customers are automatically screened for fraud and watchlist compliance when they are created. The customer object is used to: * Manage fraud and compliance * Generate paykeys * Relate payment activity * Send notifications ### Customer Identification Program (CIP) A government-mandated regulation that Straddle's KYC process complies with. Related to [AML (Anti-Money Laundering)](#aml-anti-money-laundering) compliance. Straddle Identity keeps you compliant with CIP requirements by: * Screening customers for fraud * Performing (optional) KYB and KYC * Matching against watchlist databases * Enrolling in ongoing watchlist monitoring ### Customer Review An endpoint in the Straddle API that allows you to review a customer's identity results. ### Customer Status The current state of a customer in the Straddle system, which can be one of: pending, review, verified, inactive, or rejected. ### Customer Type The classification of a customer as either an individual or a business. This determines the type of information required for verification and the available features. ## D ### Dashboard The web-based user interface provided by Straddle for account setup, activity reporting, customer management, and more. ### Decision Engine The core component of Straddle's Identity that provides automated decisioning on fraud, synthetic ID, and PII matching. ### Deposit A type of funding event where money is sent from Straddle to your business bank account for the settlement of charges. ### Device Info Information about the device used by a customer during a transaction. ## E ### Email Risk A component of Identity that provides a risk score for email addresses. ### Embed A product offering by Straddle that enables deeply integrated payment infrastructure for platforms, marketplaces, and other PSP/PayFac providers. Embed simplifies the process of integrating bank payments and managing complex money movement scenarios within an app or service. ### Error Response A standardized format for API responses when an error occurs. ### External ID A unique identifier provided by the integrating application for cross-referencing purposes between Straddle and an external system. ## F ### Fraud Score A score that assesses the risk of identity fraud associated with a transaction. ### Funding Event Represents the movement of money between Straddle and an Account. Funding events are automatically generated as part of a payment and cannot be created directly via the API. ### Funding Event Type The classification of a funding event, which can be charge deposit, charge reversal, payout return, or payout withdrawal. ### Funding Time The time that it takes for a funding event to complete. Unlike other providers, Straddle initiates funding events within 24 hours. ## G ### Global Watchlist Screening Straddle's process for identifying risk by matching entities against sanctions and enforcement lists. ## H ### HTTP Status Code A standard code returned with an API response to indicate the outcome of the request. ## I ### Identity Velocity A factor considered in Identity that monitors the frequency and recency of identity usage. ### Identity Verification The process of confirming a customer's identity. Straddle uses a combination of techniques to verify customer identities. ### Identity-Linked Payment Straddle's core concept of connecting verified customer identities directly to payment methods. Paykeys are a new kind of payment token that contain both a customer's identity and payment information. ### Industry The business sector in which an Account operates. ## K ### Know Your Business (KYB) The process of verifying the identity and suitability of business customers. ### Know Your Customer (KYC) Straddle's process of verifying the identity and suitability of customers. This process helps prevent fraud and ensures compliance with regulatory requirements. ### KYC Field Validations Comprehensive checks performed by Straddle on provided PII fields. ## L ### Linked Bank Account A bank account that has been connected to a Straddle Account. Funding events, like deposits and withdrawals, are transfers from Straddle to the linked bank account. ## M ### Metadata User-defined key-value pairs that can be attached to various objects in the Straddle system. Metadata is useful for storing additional information about an object in a structured format. ## N ### Network Alerts Notifications generated by Straddle's consortium partners related to potential risks related to a Customer or Payment. ## O ### OAuth An open standard for access delegation, used in Straddle's authentication process. ### OFAC SDN List One of the key watchlists that Straddle screens against as part of its Global Watchlist Screening process. ### Open Banking A banking practice that provides third-party financial service providers open access to consumer banking, transaction, and other financial data. ### Organization A centralized entity in Straddle that allows management of multiple accounts. Organizations provide features such as centralized dashboard, streamlined account onboarding and user management, and consolidated reporting. ## P ### Pagination The practice of dividing a large set of results into smaller, manageable "pages" in API responses. ### Pay by Bank Straddle's unified API flow for bank payments. Pay by Bank combines identity verification, open banking, and money movement into a single API. ### Paykey A secure token that links a verified customer identity to a specific payment method. Paykeys are a core component of Straddle's identity-linked payment system. ### Paykey Source The origin of a Paykey, which can be a bank account, Straddle, or a third-party provider like Plaid or MX. ### Paykey Status The current state of a Paykey in the Straddle system, which can be pending, active, inactive, or rejected. ### Payment A transaction between a Customer and a business (Account) using Straddle's payment services. Straddle supports two types of payments: charge and payout. ### Payment Date The date on which a payment is scheduled to occur. ### Payment Rail The specific method or network used to process a payment, such as [ACH](/help/ACH101/ach-basics) or RTP (Real-Time Payments). ### Payment Status The current state of a payment transaction, which can include created, pending, paid, failed, or cancelled. ### Payout A type of payment transaction where money is sent to a customer. Payouts correspond to [ACH credit](/help/ACH101/ach-credit) transactions and are created using the [`/v1/payouts`](/api-reference/payouts/create) endpoint. ### Phone Risk A component of Straddle's risk assessment that provides a risk score for phone numbers. ### Politically Exposed Person (PEP) Screening A part of Straddle's watchlist screening process to identify individuals who hold prominent public positions. ## R ### Rate Limiting Restrictions on the number of API requests that can be made within a given time period. ### Real-time Monitoring Straddle's continuous process of monitoring existing customers for changes in watchlist status. ### Representative An individual who has legal authority or significant responsibility within a business Account on the Straddle platform. ### Request Example A sample API request provided in the documentation to illustrate proper usage. ### Request ID An optional client generated header value that is returned in the API response. The request ID can be used to trace and debug individual API requests. ### Risk Score A numerical value assigned by Straddle's system to indicate potential risk associated with a transaction or customer. ## S ### Sandbox A testing environment that mimics the live Straddle platform, allowing developers to test API integrations without affecting real accounts or transactions. The Sandbox is available to all Straddle accounts via the URL [https://sandbox.straddle.com](https://sandbox.straddle.com). ### Sanctions and Enforcements Screening Straddle's process of screening consumers and businesses during onboarding against various sanctions lists. ### Status Details Additional information about the current status of an object in the Straddle system. ### Status History A record of status changes for an object over time. ### Straddle Account ID A unique identifier for a Straddle account. This is the primary identifier for an account in the Straddle system. This value can be used by Platforms to originate API requests to Straddle on behalf of an Account by including the header `X-Straddle-Account-Id`. ### Straddle Identity An all-in-one identity verification system that provides a risk score for physical addresses, email risk, phone risk, and more. Identity uses a combination of machine learning, big data, and predictive analytics to accurately verify identities and prevent fraud. See also [KYC (Know Your Customer)](#know-your-customer-kyc) and [KYB (Know Your Business)](#know-your-business-kyb). ### Support Channels The various methods provided by a business during Account onboarding for customer support, such as email, phone, or chat. ### Synthetic ID Detection Custom models trained with consortium data to tackle fake and randomized synthetic patterns to produce highly accurate, real-time, actionable risk scores and reason codes, with 90% auto-capture in the riskiest 3% of users. ### Synthetic Identity Risk Score A score that predicts the probability that provided PII corresponds to a fictitious person. ## T ### Terms of Service The agreement that users must accept to use the Straddle platform. ### Third-Party Fraud Also known as identity fraud, where an imposter uses a real person's information for financial gain. ### Transaction A financial operation processed through the Straddle platform, such as a charge or payout. ## W ### Watchlist Screening The process of checking customer information against various sanctions and enforcement lists. ### Watchtower Straddle's transaction monitoring risk engine that provides built-in balance confirmation, real-time fraud detection, and risk assessment. ### Webhook A mechanism for receiving real-time notifications about events in the Straddle system. ### Withdrawal A type of funding event where money is pulled from an external bank account by Straddle, typically for payouts. Need help with a specific term? Use Ctrl+F (or Cmd+F on Mac) to quickly search for any term in this glossary. # MSB: A fintech guide Source: https://docs.straddle.com/help/Reference-Materials/money-service A fintech guide to Money Service Business (MSB) requirements, including money transmitter licenses, FinCEN registration, and ongoing compliance obligations. If you work in fintech, you may have heard the phrase "money transmitter." If you handle and send money for others, it's important to know the basics of money transmission licenses (MTLs). But MTLs are actually a subset of "money services businesses" or MSBs. If a fintech isn't careful, it may trigger MSB (and MTL) obligations unintentionally. In this guide, we'll walk through MSBs and cover what fintech operators should know. **Quick summary** If you're a fintech that handles other people's money, you'll want to make sure you're complying with MSB laws. Practically, this means you should: * Determine if you might count as an MSB * Consider whether any bank accounts holding customer funds are set up as "for benefit of" accounts * Determine if you fit the state agent of payee exemptions * If you're an MSB or money transmitter, register with FinCEN, implement an AML program, and comply with all relevant state laws * If you need MTLs, make sure your databases are set up in advance to support your state reporting needs * Talk to a lawyer! Every product has its own considerations ## What is a money services business (MSB)? Money services businesses (MSBs) are non-bank businesses that let customers store, transfer, and exchange money or other stores of value. Under federal law, a business can count as an MSB if it does one or more of the following: * Deals or exchanges foreign currency * Cashes checks * Issues or sells traveler's checks, money orders, or stored value * Provides or sells prepaid access (e.g. prepaid cards) * Is a money transmitter * Is the US postal service The most relevant categories for fintechs are **money transmitters** and **prepaid access providers**. The others are much less common for fintechs. For example, the sellers of prepaid access category generally applies to retail stores like Walmart that sell prepaid cards. However you might trip into this category if you accept funds from customers into your operating accounts before passing them onto FBO accounts at your bank partners. This is a good reminder of why it's important to work with an expert to help structure your funds flows and bank accounts. ### MSB exceptions There are a few types of companies that are explicitly carved out from being classified as MSBs, such as: * Certain entities registered and regulated by the SEC or CFTC or similar foreign financial regulator * Individuals engaged in money transmission on an infrequent and not-for-profit basis * Banks (also exempt from having to register as MSBs) ## Why do MSBs matter? MSBs are required to register with the Financial Crimes Enforcement Network (FinCEN) and comply with the Bank Secrecy Act's (BSA) requirements, including: * Having an anti-money laundering (AML) program * Performing KYC/KYB on customers * Complying with state licensing laws (which can be onerous) Failing to register as an MSB carries its own risk of fines and penalties. Additionally, large banks and MSBs like Ripple and Western Union have paid hundreds of millions in fines for AML failures, and AML obligations can be triggered when you count as an MSB. ## What is a money transmitter? Under federal law, a money transmitter is defined as someone who receives money from one person and transmits it to another. The definition is purposely circular to give regulators wide latitude to label something money transmission. Money transmission can be hard to determine based on a definition alone, so let's look at examples: **Digital wallet companies** are generally money transmitters. They accept customer funds and move those funds to recipients, allowing customers the ability to hold funds in their wallets. Examples include PayPal and Block (formerly known as Square). **Cross-border remittance companies** like Western Union and MoneyGram also hold money transmitter licenses. They accept funds from one party and handle sending them to another, often in a different country. ### Money transmitter exceptions There are some potential paths fintechs should be aware of if they are interested in steering away from money transmission requirements. The definition of "money transmitter" has a few exceptions that have developed over the years, including: * Companies that only provide technology layers that money transmitters use * Payment processors that facilitate payments for goods and services through a clearance and settlement system * Companies that only accept and send funds that are integral to the sale of goods or services (for example, a P2P micro-lending platform) #### For the benefit of (FBO) accounts To steer into the technology layer path, fintechs can work with bank partners to set up "for the benefit of" (FBO) accounts. These are custodial accounts that let a company manage funds on behalf of others without technically having legal ownership of the account. To set up an FBO account, you generally need to: 1. Include who the account is on behalf of in the legal documents setting up the account 2. Have the bank's taxpayer identification number (aka, an EIN) as the relevant tax ID when opening the account Not every bank will offer this service, and some banks who do offer this service will still look to put limits on your product offering. So it is important to discuss FBO options and limits with potential bank partners in advance. From time to time, some regulators have tried to take the view that you have control over an FBO, even if it's in your bank partner's taxpayer ID number. Working with experienced outside counsel can help you navigate these issues and also respond to regulators who may take this aggressive approach. ## Money transmitter licenses (MTLs) and state laws Money transmitters are required to register for a money transmitter license (MTL) where their activity falls within the state definition of a money transmitter. Almost all states have their own money transmitter laws, and they are far from identical. State requirements will vary on topics like: * Posting a bond (i.e., a cash deposit or insurance covering the amount of the deposit) * Maintaining a minimum net worth * Applying for a license * Undergoing regular exams * Filing reports with the state ### State exemptions There are two carve outs that help: 1. **FBO account construct** - The FBO account structure discussed above can prevent you from being a money transmitter in some states 2. **Agent of the payee exemption** - Many states have an "agent of the payee" exemption from money transmission licenses #### Agent of the payee exemption Under the agent of the payee exemption, you generally don't need a money transmission license if: * You have a contract with the payee that says you can collect payments for them, or you're appointed as their agent * The relevant money is paid for goods and services the payee provided **Example:** A platform that handles bill pay payments. Person A signs up with the platform and uses it to send a bill to Person B for work Person A did. Person B pays the platform, and the platform sends the money to Person A. The platform receives and sends money for others, which is money transmission. However, the platform is acting as an agent of Person A, the payee, and payments are made for services. Accordingly, the agent of payee exemption might apply under state laws. This agent of payee exemption can cover use cases like: * Payment processors * Payroll facilitators * Bill pay companies The Conference of State Bank Supervisors (a trade organization representing state bank regulators) has a handy map of states with agent of payee exemptions. States often have longstanding judicial precedent that establishes and protects the agent of payee model. Due to employee turnover, and sometimes aggressive posturing by staff, state regulators sometimes forget about this case law and will try to reach beyond the limits of their authority. There are a handful of law firms with deep experience in helping companies on these matters, and hiring them can help you successfully navigate these exemptions. ## What is a prepaid access provider? Prepaid access providers also qualify as MSBs, and this category includes companies that offer prepaid cards and other prepaid accounts such as digital wallets. Unless a company fits in an exemption, this means companies that provide prepaid cards or digital accounts also need to register with FinCEN as an MSB and stand up an AML program. For those companies experimenting with product-market-fit, it may be helpful to know that certain prepaid card programs are excluded from the prepaid access category. The rationale behind these exclusions is that the structure of these programs prevents large-scale or dangerous money laundering. Companies who want to pursue these exemptions can work with experienced counsel. Some card issuing processors are also familiar with these exemptions and can help their customers structure programs. ## Tips for first-time MSBs If you and your counsel determine that you need an MSB registration and related state licenses to operate your business, you might benefit from the following best practices: ### Records management **Keep digital copies** of all files you submit to federal and state regulators. Google Drive, Box and other online storage services make this a lot easier than it used to be. ### Organization **Get organized.** MSBs need to make hundreds of reports and filings each year, across all of the U.S. states. FinCEN also requires you to update your registration on a specific cadence. You may want to use a spreadsheet or calendar invites to track when filings and reports are due, and what forms need to be filled out. ### Data requirements **Check your data needs early.** All those monthly, quarterly and annual reports require data and the formats and definitions often vary. Check first to see if your product and back-end databases are set up to capture all of the necessary information. Then build your SQL queries or other reporting tools to help your compliance team pull data as needed. ### Product changes **Stay on top of design and copy changes.** Some states will require you to submit advance notice of new products, even pilot and beta offerings. And some states like California will require you to have design changes to your receipts approved in advance. ### Examinations **Prepare for onsite exams.** State regulators will conduct regular examinations at your headquarters location. Make a pitch deck to help educate examiners about the history of your company. Make sure your deck walks through how your product operates, especially if you have a B2B money transmission or prepaid access product. ### Escheatment compliance **Don't cheat escheatment.** Every state regulator will ask you for a copy of your last unclaimed property report, regardless of whether you have reporting obligations in that state. Some states will have negative reporting obligations—meaning you need to file a report even if you don't have any unclaimed property to escheat. ### Communication **Don't miss your mail.** Regulators will often forward complaints or routine inquiries to the contacts listed on your license. If you list a general email inbox, make sure you are checking it regularly (or better yet, forward it to a group of individuals responsible for your licenses). Regulators rightfully get upset if you don't respond to these messages, even if the lack of response is an innocent mistake or error. Entities already subject to certain regulators, like bank regulators or the SEC, are not required to register with FinCEN. Practically, this means banks aren't required to register with FinCEN. **Disclaimer:** This post is for information purposes only and is not legal advice. Every situation is unique, so you should consult a lawyer. Consider working with experienced fintech attorneys for guidance specific to your situation. # Check the status of your production request Source: https://docs.straddle.com/help/Reference-Materials/production Check the status of your Straddle production access request, application review, or full account approval and find next steps with the onboarding team. # Check the status of your production request If you've submitted a product request, application, or full access request and want to check the status, we're here to help. ## How to check the status of your request If you've submitted a product request, application, or full access request and are looking to check the status, we're here to help. At this time, request statuses are **not visible in the customer support system**, so our team members in chat or email won't be able to provide updates directly. ## What to do To check the status of your: * Product access request * Full application setup * Any submitted onboarding forms or approvals **Email our onboarding team directly:** **Contact our onboarding team:** 📩 [**onboarding@straddle.com**](mailto:onboarding@straddle.com) They'll be able to review your request and provide an accurate update. **Pro tip:** Include any relevant details (like your company name, request type, or submission date) in your email to help the onboarding team respond quickly. *** # Beneficial Ownership Requirements Source: https://docs.straddle.com/help/Reference-Materials/representatives Legal requirements for identifying beneficial owners and control persons of business accounts under the FinCEN Customer Due Diligence (CDD) rule. ## Overview There is an industry-wide requirement for banks and payment providers to know the individuals they do business with. The Financial Crimes Enforcement Network (FinCEN) has issued a Customer Due Diligence (CDD) rule to amend existing BSA regulations. This rule clarifies and strengthens customer due diligence requirements for financial institutions. The rule outlines explicit customer due diligence requirements and imposes a new requirement to identify and verify the identity of beneficial owners of legal entity customers, subject to certain exclusions and exemptions. FinCEN intends that the legal entity customer identify its ultimate beneficial owner(s). Straddle is legally obligated to follow a specific set of steps before we can open a Straddle payments account. ## Key points The CDD Rule, which amends Bank Secrecy Act regulations, aims to improve financial transparency and prevent criminals and terrorists from misusing companies to disguise their illicit activities and launder their ill-gotten gains. The CDD Rule requires covered financial institutions and service providers like Straddle to identify and verify the identity of the natural persons (known as beneficial owners) of legal entity customers who own, control, and profit from companies when those companies open accounts. ## Core requirements The CDD Rule has four core requirements. It requires covered financial institutions to establish and maintain written policies and procedures that are reasonably designed to: 1. **Identify and verify customer identity** - Establish the identity of all customers opening accounts 2. **Identify beneficial owners** - Identify and verify the identity of the beneficial owners of companies opening accounts 3. **Understand customer relationships** - Understand the nature and purpose of customer relationships to develop customer risk profiles 4. **Conduct ongoing monitoring** - Monitor to identify and report suspicious transactions and maintain updated customer information Financial service providers must identify and verify the identity of any individual who owns 25 percent or more of a legal entity, and/or an individual who controls the legal entity. ## What is a beneficial owner? A beneficial owner is an individual, if any, who holds 25% or more equity ownership of your business and/or at least 1 individual who has "significant control." ### Who has significant control? There will always be an individual with significant responsibility for managing the legal entity such as: * Chief Executive Officer * Chief Financial Officer (CFO) * Chief Operating Officer * Managing Member * Vice President * Treasurer * Any other individual who regularly performs similar functions ### Why is this information required? To help the government fight financial crime, Federal regulation requires covered financial institutions to obtain, verify, and record information about the beneficial owners of legal entity customers. Legal entities can be abused to disguise involvement in: * Terrorist financing * Money laundering * Tax evasion * Corruption * Fraud * Other financial crimes Requiring the disclosure of key individuals who own or control a legal entity (the beneficial owners) helps law enforcement investigate and prosecute these crimes. ## What is a legal entity? A legal entity is a corporation, limited liability company, partnership, and any other similar business entity formed in the United States or a foreign country. ## Who needs to provide this information? We'll request this information from: * The person who opens a new Straddle account on behalf of a legal entity * The primary account user for an existing account Users must provide the ultimate beneficial owner who must be a natural person. ## Required information We need to collect the following information for at least 1, and a maximum of 5 beneficial owners: | Information Required | Details | | - | - | | Name | Full legal name | | Address | Current residential address | | Date of birth | Complete date of birth | | Identification | Social Security Number (or passport number for foreign persons) | ### Beneficial owner criteria Each beneficial owner must be a natural person (not a legal entity) who satisfies the following criteria: * **Ownership requirement**: Each individual, if any, who directly or indirectly owns 25% or more of the equity interests of your legal entity company * **Control requirement**: An individual with significant responsibility for managing your legal entity company (e.g., CEO, CFO, COO, Managing Member, General Partner, President, Vice President, or Treasurer) You must provide information for individuals who satisfy the above ownership criteria, either directly or indirectly, through multiple legal entities. ## Multi-level ownership example When a business is owned by another company, you must trace ownership through multiple corporate structures: **Example scenario:** * Allan owns 30% of Customer B indirectly through his direct ownership of Company A → Allan is a beneficial owner * Betty owns 20% indirectly through Company A plus 16⅔% through Company B (total 36⅔%) → Betty is a beneficial owner * Carl and Diane each own only 16⅔% indirectly through Company B → Neither is a beneficial owner (below 25% threshold) ## Privacy and security ### Will credit scores be affected? Straddle never uses personal information to generate a hard credit inquiry. Straddle uses the information you provide strictly for ID verification purposes. ### Is the information safe? We follow industry best practices for data security and are subject to annual security audits. All Straddle application data: * **In-transit**: Protected with TLS 1.2 Asymmetric Encryption * **At-rest**: Protected by Transparent Data Encryption (TDE) in Microsoft Azure ## Exemptions from CDD rule The following entities are excluded from the definition of "legal entity customer" since beneficial ownership information is generally available from other credible sources: ### Financial institutions and government entities * Financial institutions regulated by a Federal functional regulator or State bank regulator * Departments or agencies of the United States, any State, or political subdivisions * Entities established under U.S. or State laws that exercise governmental authority * Non-U.S. governmental departments, agencies, or political subdivisions engaging only in governmental activities ### Publicly traded and registered entities * Entities whose common stock is listed on NYSE, American, or NASDAQ stock exchanges * Entities where at least 51% of common stock is owned by a listed entity * Issuers of securities registered under Section 12 of the Securities Exchange Act of 1934 * Investment companies registered with the SEC * Investment advisers registered with the SEC * Exchanges or clearing agencies registered under the Securities Exchange Act ### Regulated financial services * Registered entities, commodity pool operators, commodity trading advisors with CFTC * Public accounting firms registered under the Sarbanes-Oxley Act * Bank holding companies or savings and loan holding companies * Insurance companies regulated by a State * Financial market utilities designated by the Financial Stability Oversight Council * Foreign financial institutions where regulators maintain beneficial ownership information ### Limited requirements The following legal entity customers are subject only to the "controlling person" portion of the beneficial ownership requirement: * Pooled investment vehicles operated or advised by non-excluded financial institutions * Nonprofit corporations or similar entities that have filed organizational documents with appropriate State authorities ## Additional resources Read the complete CDD requirements for financial institutions View frequently asked questions about customer due diligence requirements # ACH return codes and Nacha thresholds Source: https://docs.straddle.com/help/nacha-rules/ach-return Understand ACH returns, including unauthorized and administrative return codes, Nacha compliance thresholds, and how to monitor and reduce return rates. ## What are ACH returns? An ACH return is a message that lets Straddle know the ACH Network couldn't collect funds from or deposit funds into a Receiver's account. Typically, an ACH return comes from the RDFI (customer's bank), but in some instances the ODFI (your bank) or even the ACH Operator itself might send such a message. You can think of a return being similar to a chargeback for credit cards - it is something that as a business you hope to avoid, but at times can be unavoidable. Returns being initiated by the RDFI can only be initiated during specific timeframes, due to rules set by the Nacha operating guidelines. ## Why do ACH returns happen? ACH returns typically occur in two main scenarios: **Immediate identification by RDFI** The RDFI can quickly identify when a return needs to be initiated in situations such as: * Insufficient funds in the receiving party's account * Legal name on the account doesn't match the legal name included within a payment The RDFI acts quickly to ensure these returns are highlighted and sent to Straddle to handle accordingly. **Receiver-initiated returns** The receiving party can reach out to their bank to request a return on a payment. This scenario might include times when the receiving party alerts the RDFI that they had not initially provided permission for a payment to occur on their account. There are approximately 70 unique return codes that help the Originator identify the reason for a return. Each return code is specific to certain entry types and has specific time frames for return. ## ACH return thresholds Nacha rules require that each account maintain a percentage of ACH debit returns under specific thresholds: **Administrative Returns** must stay below **3%**. This percentage is calculated based on ACH debit returns for the preceding 60 days on return reason codes: R02, R03 and R04. **Unauthorized Returns** must stay below **0.5%**. This percentage is calculated based on ACH debit returns for the preceding 60 days on return reason codes: R05, R07, R10, R29 and R51. **Overall Returns** must stay below **15%**. This percentage is calculated based on ACH debit returns for the preceding 60 days and includes all return reason codes. This includes NSF (non-sufficient funds) returns (reason codes R01 and R09). ## Common return codes | Reason | Return Code | SEC Code | Action | | - | - | - | - | | **Insufficient Funds** - Available balance not sufficient to cover amount of debit entry | R01 | ALL | May initiate a new ACH entry; must remain within reinitiation limits outlined in Article 2 of the ACH Rules and be reinitiated within 180 days of the Settlement Date of the original entry | | **Account Closed** - Previously active account has been closed | R02 | ALL | Stop initiation of entries. Contact customer to obtain authorization for another account | | **No Account** - Account number structure is valid, but doesn't match individual or open account | R03 | ALL | Stop initiation of entries. Customer should be contacted for correct account information | | **Invalid Account** - Account number structure not valid; edit of check digit or number failed | R04 | ALL | Stop initiation of entries until account number/structure is corrected | | **Payment Stopped** - The customer has requested the stop payment of a specific ACH debit entry | R08 | ALL | Contact the customer to identify the reason for the stop payment and obtain authorization before reinitiating the entry | | **Uncollected Funds** - Sufficient ledger balance exists, but value of uncollected items brings available balance below amount of debit entry | R09 | ALL | May initiate a new ACH entry; must remain within limits for reinitiating entries outlined in Article 2 of the ACH Rules and be reinitiated within 180 days of the Settlement Date of the original entry | | **Account Frozen/Entry Returned Per OFAC Instruction** - Access to the account is restricted due to action by RDFI or by legal action | R16 | ALL | Stop initiation of entries. Terms of authorization may offer recourse outside the ACH Network. OFAC may have instructed the payment be returned | | **File Edit Record Criteria/Entry with Invalid Account Number Initiated Under Questionable Circumstances** - Fields edited by the RDFI cannot be processed or RDFI suspects payment may be fraudulent | R17 | ALL | Identify and correct errors prior to initiation of further entries. Errors are identified in the Addenda Information field of the Addenda Record. If this field contains 'QUESTIONABLE,' investigate validity of transaction | | **Non-Transaction Account** - RDFI policies or regulations restrict activity to account indicated | R20 | ALL | Stop initiation of entries. Contact customer for new account information | | **Duplicate Entry** - Entry is a duplication. The trace number, date, dollar amount, etc. match another entry | R24 | ALL | If entry is a duplication, accept the return. If the entry has already been reversed, your company should work with your ODFI to contact the RDFI to determine a solution | ## Unauthorized returns An unauthorized return occurs when the RDFI asks for the amount debited from the bank account of the Receiver to be returned to the account from which it was withdrawn. In most situations, the return is initiated when the Receiver submits a signed statement to their bank claiming that the transaction is not authorized. These returns have a far longer "return window" - the Nacha rules allow for automatic reversal of unauthorized transactions for up to 60 days. If a consumer completes a Written Statement of Unauthorized Debit, the RDFI returns the debit entry as Unauthorized. If you can prove that there is, in fact, valid authorization to debit the account, you should pursue the issue outside of the ACH Network. This could include requesting a copy of the signed statement from the RDFI and seeking legal advice on how to handle the collection of authorized funds from the consumer. ### Unauthorized return codes | Reason for Return | Return Code | SEC Code | Action by Originator | | - | - | - | - | | **Unauthorized Debit to Consumer Account Using Corporate SEC Code** - A debit entry that uses a corporate SEC code was transmitted to a consumer account but was not authorized by the consumer | R05 | CCD | Stop initiation of entries | | **Authorization Revoked** - Customer who previously authorized an entry claims authorization has been revoked | R07 | PPD, WEB | Stop initiation of entries until new consumer authorization is obtained. Depending upon the terms of the original authorization, your company may have recourse for collection outside the ACH Network | | **Customer Advises Originator is Not Known to Receiver and/or Originator is Not Authorized by Receiver to Debit Receiver's Account** - Receiver doesn't know or have a relationship with the Originator. No authorization provided. Signature on source document or written authorization is not authentic, valid or authorized | R10 | PPD, WEB | Stop initiation of entries | | **Customer Advises Entry Not in Accordance with Terms of the Authorization** - Authorization obtained, but error in payment (e.g. wrong amount; debit date before authorized; incomplete transaction; improper source document or exceeds reinitiation attempts) | R11 | PPD, WEB | Your company may initiate a new entry to correct the underlying error without obtaining a new authorization. Corrected entry must be originated within 60 days of the Settlement Date of the R11 return entry | | **Credit Entry Refused by Receiver** - Customer declines transaction because amount is inaccurate, results in overpayment, account is in litigation or Originator is not known to the Receiver | R23 | ALL CREDIT ENTRIES | Obtain customer authorization prior to reinitiating the entry | | **Corporate Customer Advises Not Authorized** - Corporate customer has notified RDFI that a specific entry is not authorized | R29 | CCD | Stop initiation of entries until subsequent authorization has been obtained. If a valid authorization exists, your company may have recourse outside the ACH Network | # ACH Rules & Regulations Source: https://docs.straddle.com/help/nacha-rules/ach-rules A comprehensive guide to Nacha rules and regulations governing ACH entry transmission, settlement, and obligations of originators and financial institutions. There are many rules and regulations governing the transmission of ACH entries. This guide covers the rules and regulations that have the most impact on financial institutions. ## Overview of applicable regulations The following regulations and rules apply to ACH transactions: * **ACH Rules** - Primary source for Commercial ACH Network regulations * **Office of Foreign Assets Control (OFAC)** - Economic sanctions and embargo programs * **Regulation E and Electronic Fund Transfer Act (EFTA)** - Consumer protection for electronic transfers * **State law** - Additional state-specific requirements * **Title 31 CFR Part 210** - Federal government agency ACH usage * **Uniform Commercial Code Article 4A (UCC 4A)** - Corporate ACH transactions * **USA PATRIOT Act** - Anti-terrorism and money laundering provisions ## ACH Rules The ACH Rules serve as the primary source for rules and regulations for the Commercial ACH Network and are contract law that is made binding by agreements. Commercial ACH entries are originated by the private sector, which includes individuals, companies and state and local governments. The ACH Rules define the obligations and liabilities of each financial institution, including a provision to perform an annual audit, and provide a mechanism for a receiving institution to return an entry to the sending institution. The ACH Rules help reduce risk in the Network and protect financial institutions from potential loss. ## Office of Foreign Assets Control (OFAC) The U.S. Department of the Treasury, Office of Foreign Assets Control, administers economic sanctions and embargo programs that require assets and transactions involving interests of targeted countries, targeted country nationals and other specifically identified companies and individuals to be frozen. ### SDN List compliance OFAC maintains a list of Specially Designated Nationals and Blocked Persons (SDN List) to assist financial institutions in identifying blocked parties. All U.S. participants in the ACH Network may be held accountable for sanction violations and must understand their compliance obligations. As an RDFI, the financial institution should have a process in place to determine whether any of its account holders are identified as a blocked party on a current SDN List. Financial institutions are strongly encouraged to obtain a current SDN List and other compliance information directly from OFAC. ## Regulation E and Electronic Fund Transfer Act (EFTA) Regulation E carries out the purpose of the EFTA, which establishes the basic rights, liabilities and responsibilities of consumers who use electronic fund transfer services. The primary objective of this act and regulation is the protection of individual consumers engaging in electronic fund transfer services. ### Key areas covered Regulation E addresses the responsibilities of financial institutions regarding: * Disclosures to consumers * Stop payment procedures * Unauthorized debit transactions to consumer accounts * Process for resolving errors ## State law Some state laws may impact ACH transactions if the law is more restrictive or provides greater consumer protection than other prevailing rules or regulations. ### Common state requirements * **Direct Deposit mandates**: Some states allow companies to mandate employees to be paid by Direct Deposit; however, most state labor codes restrict companies from offering only Direct Deposit * **Tax payments**: Many states have mandated state taxes paid by businesses and corporations be initiated through the ACH * **Legal guidance**: The states' Attorneys General Offices can provide specifics on state-specific requirements ## Title 31 Code of Federal Regulation Part 210 (31 CFR Part 210) 31 CFR Part 210 provides the regulatory foundation for the use of the ACH Network for federal government agencies. It defines the rights and liabilities of agencies, Federal Reserve Banks, financial institutions and the public in connection with ACH entries. ### The Green Book The Green Book is the procedures manual for financial institutions processing federal government payments. Among the procedures covered by the Green Book are: * Handling of federal government reclamations * Enrollment in federal government benefit payment programs By accepting a federal government benefit payment, a financial institution agrees to be bound to 31 CFR Part 210, and therefore, must adhere to these procedures. ## Uniform Commercial Code Article 4A (UCC 4A) Uniform Commercial Code (UCC) is a series of state laws that govern commercial transactions. Article 4A of the UCC governs corporate ACH transactions that are referred to as "corporate wholesale credit entries." ### Transaction identification RDFIs may identify these transactions by Standard Entry Class Codes: * **CCD** - Corporate Credit or Debit * **CTX** - Corporate Trade Exchange ### Security requirements UCC 4A also addresses the 'commercially reasonable security procedures' that must be in place for ACH Origination to occur. ## USA PATRIOT Act The Uniting and Strengthening America by Providing Appropriate Tools Required to Intercept and Obstruct Terrorism Act of 2001 establishes a wide variety of ways to combat international terrorism. ### Title III provisions Title III—International Money Laundering Abatement and Anti-Terrorist Financing contains provisions relating to money laundering and terrorist access to the financial system. This section affects financial institutions with regard to information sharing and customer identification programs (CIPs). ### Customer Identification Program requirements CIPs require financial institutions to complete the following prior to opening a new account: 1. **Verify identity** - Verify the identity of any person seeking to open an account 2. **Maintain records** - Maintain records of the information used to verify identity 3. **Consult terrorist lists** - Consult government-known or suspected terrorist lists to determine whether the customer appears on any such list ## Regulatory conflicts and precedence **Rule of thumb**: When conflicts are found among these various rules and regulations, the most restrictive rule or regulation applies. In other words, the one that benefits or provides the most protection to the consumer would be applied. ## The future of ACH Over the years, consumer and corporate customers have become more and more aware of the advantages of the electronic payments network. As a result, customers are more demanding and financially savvy. ### ACH Network capabilities The ACH Network provides the ability to: * Directly deposit employee payroll * Permit automated bill payment services * Allow for purchases online * Enable companies to perform cash concentration * Facilitate corporate-to-corporate payments As migration from paper to electronic payment continues, the cost-effective ACH Network will grow and enable innovation that strengthens the industry with creative payment solutions. # Nacha ACH Appendix Source: https://docs.straddle.com/help/nacha-rules/nacha-appendix A complete reference for the ACH file format, batch header and entry detail records, and terminology drawn from Nacha's Quick Reference rule guides. ## ACH file format The ACH file format consists of multiple levels of information that ensure proper processing and settlement of electronic payments through the ACH Network. ### Nacha batch/file level information Entity or individual originating batch of entries (Originator) Number that uniquely identifies the Originator to the ODFI (tax ID number often used) Three-digit Julian date which represents the date funds are actually settled by the ACH Operator (i.e., Federal Reserve Bank or The Clearing House) Distinguishes between Commercial and Federal Government Originators: * **1** = Commercial * **2** = Federal Government entity or agency Three-character alpha code which distinguishes application type and identifies which rules apply Describes the entry and should be provided to the account holder Date Originator intended entries to settle (actual Settlement Date may differ) Total number of entries and addenda records in the file (or batch) Value of entries in the file (or batch) for reconcilement ### Entry level information Name of account holder Number that identifies Receiver to the originating entity 15-digit trace number that uniquely identifies an entry (first eight digits identify the routing number of ODFI or government agency) Identifies whether entry is a debit or credit to: * Demand account * Savings account * Financial institution's general ledger account * Credit or reversal to a loan account Number of account for entry to be posted Dollar value of the entry ## Suggested resources Workbook designed to assist financial institutions in completing required annual audits. Available through your Payments Association. Provides quick access to routing numbers and contact information for financial institutions that participate in the ACH Network. Seven-card series covering ACH Returns, NOCs, Special Exceptions, Electronic Check Applications, IAT, WEB and TEL. Available through your Payments Association. Workbook designed to assist financial institutions in completing ACH Risk Assessments as required by regulators. Available through your Payments Association. Guide for analyzing risks associated with ACH processing and recommendations for risk control methods and procedures. Available through your Payments Association. Complete ACH Rules documentation. Available through your Payments Association. Website designed to assist financial institutions, businesses and consumers in understanding electronic payments. U.S. Treasury campaign to motivate federal benefit recipients to use direct deposit. Comprehensive guide for financial institutions processing Federal Government ACH payments and collections. Listing of targeted countries, nationals and entities requiring asset and transaction freezing. Source information for UCC 4A with commentary. Available through your Payments Association. ## Glossary ### A A single-entry ACH debit initiated by an Originator to a Receiver's account pursuant to a source document (i.e., check/sharedraft) provided to the Originator by the Receiver via U.S. mail, at a dropbox location or for an in-person bill payment at a manned location. The funds transfer system governed by the ACH Rules of Nacha which provides for the inter-financial institution clearing of electronic entries for participating financial institutions. An organization that provides processing services for the ACH Network. The Federal Reserve Bank and Electronic Payment Network (EPN) are examples of ACH Operators. An ACH application using Standard Entry Class codes ACK and ATX which allows Originators to receive electronic acknowledgments from Receiving Depository Financial Institutions (RDFIs) advising receipt of corporate credit payments (CCD and CTX, respectively). The Standard Entry Class code used by the Receiving Depository Financial Institution (RDFI) to acknowledge receipt of corporate credit entries received in the CCD format. An ACH record type that carries supplemental data needed to completely identify an account holder(s) or provide information concerning a payment. Acronym for American National Standards Institute. The Standard Entry Class code for Accounts Receivable Entries. The Standard Entry Class code used by the Receiving Depository Financial Institution (RDFI) to acknowledge receipt of corporate credit entries received in the CTX format. The funds transfer system governed by the ACH Rules of Nacha which provides for the inter-financial institution clearing of electronic entries for participating financial institutions. A credit or debit enrollment entry initiated by a participating Depository Financial Institution (DFI) to a federal government agency on behalf of an account holder at the DFI. Entries must include at least one addenda record that relays information pertaining to the account holder on whose behalf the ENR is initiated. An optional, variable format field of the MICR line of a check or sharedraft. It is positioned to the left of the routing number and data located in this field is bracketed by on-us symbols. The information contained in the Auxiliary On-Us Field is determined by the financial institution and may contain the check serial number or a financial institution code for the account. ### B An ACH application that allows Originators (merchants, retailers, etc.) to initiate single-entry ACH debits by using the check as a source document when appropriate notice is provided in person by the Originator to the Receiver (check writer) for a purchase made at the point-of-sale or at a manned bill payment location. With reference to a Depository Financial Institution (DFI), any day on which such DFI is open to the public for carrying on substantially all its banking functions; and with reference to an ACH Operator, any day on which the appropriate facility of such ACH Operator is being operated. A group of records or documents considered as a single unit for the purpose of data processing. The Standard Entry Class code for Back Office Conversion Entries. A bureau of the U.S. Department of the Treasury that is the government's financial manager and which manages the government's payments and collections. ### C The Standard Entry Class code for Corporate Credit or Debit. A commercially reasonable system, technology, practice or procedure is one that corresponds to commonly accepted commercial practices among commonly situated Originators conducting similar types of business. A security procedure for the transmission of payment orders which meets the relevant tests under the Uniform Commercial Code Article 4A. The record(s) contained within an ACH file that describes the Originator(s) of an ACH transaction(s) and the types of transactions within that batch. The Standard Entry Class code for Automated Notification of Change or Refused Notification of Change. An ACH debit or credit entry initiated by an organization to consolidate funds of that organization or to fund outlying accounts. It is also used for corporate payments. CCD+ is a CCD entry with one addenda record. Payments made through the ACH Network by trading partners, normally using the CCD, CCD+ or CTX formats. An automated corporate payment that supports the transfer of funds (debit or credit) within a trading partner relationship in which a full ANSI ASC X12 message or payment-related UN/EDIFACT information is sent with the funds transfer. A CTX transaction can have up to 9,999 addenda records. The risk that a party to a transaction cannot provide the necessary good funds, as previously committed by files originated, in order for settlement to take place. The Standard Entry Class code used for Corporate Trade Exchange Entries. ACH credit entries initiated by a consumer through direct contact with an Originator such as a bill paying or home banking system. ### D The electronic exchange of information between two data processing points (computers). An automated notice of death sent by a federal government agency to a financial institution to notify the financial institution that a recipient of benefit payments from that agency (and possibly other agencies as well as private sector payers) has passed away. An entry to request transfer or removal of funds from an account. A process used to restrict debits to a demand deposit account. This application can be utilized by a collecting institution for the collection of certain checks when those checks have been lost or destroyed or cannot be processed through image exchange. Deposit of funds to a consumer's account for payroll, travel reimbursement, government benefits, tax and other refunds, and annuities and interest payments. Use of funds for making a payment. Individuals or organizations can send or receive a Direct Payment as an ACH credit or debit. Basically, any ACH payment that is not a Direct Deposit is known as a Direct Payment. The Standard Entry Class code used by the Federal Government for Death Notification Entries. ### E A generic term for an ACH debit to a Receiver's account that is originated on the Internet, at the point-of-sale, over the telephone, or by bill payment sent through the mail or dropped in an unattended drop box. Acronym for Electronic Data Interchange. The date on which the Originator requests ACH transactions be posted to the Originator's and Receiver's accounts. The ACH Operator overrides this date if the Effective Entry Date is not a banking day. A computer to computer exchange of standard business data according to agreed upon data formats. Any transfer of funds initiated through a terminal, telephone or computer for the purpose of instructing or authorizing a financial institution to debit or credit an account. The law passed by the U.S. Congress in 1978 which set out the rights and obligations of consumers and their financial institutions regarding the use of electronic systems to transfer funds. This act is implemented in the Federal Reserve Bank's Regulation E. A term that refers to a computer-generated algorithm that allows secure communication between parties. The Standard Entry Class code used for Automated Enrollment Entries. An electronic item representing the transfer of funds in the ACH Network. Procedures required under Regulation E for resolving a consumer's allegation that entries were improperly charged to the consumer's account. Any entry that requires special attention or processing, such as return entries, stop payments, notifications of change, dishonored returns, etc. A written agreement that is in place between the Originator and Receiver or when the Receiver has purchased goods or services from the Originator in the past two years. A maximum total limit established by an Originating Depository Financial Institution (ODFI) for each of its Originators beyond which the ODFI is unwilling to process additional ACH files. This limit is established as a fraud and error control under the ODFI's risk management program. The ACH Rules require the ODFI to monitor this limit across multiple settlement dates to ensure that a particular Originator does not inadvertently exceed it. ### F - H Abbreviation for Financial Institution. An organization that can originate and receive payments such as a bank, savings and loan and/or credit union. One or more consecutive character positions within an ACH entry mapped to contain specific information. A group of ACH entries sorted for delivery to an ACH receiving point. The last record of an ACH file indicating termination of the information within the file. The first record of an ACH file containing information necessary to route, validate and track ACH items contained within the file. An ACH application that involves the transmission of remittance information in the addenda of an ACH transaction using ANSI standards. An organization that can originate and receive payments such as a bank, savings and loan and credit union. The time at which the funds from an electronic funds transfer are made available to the customer. A campaign sponsored by the U.S. Department of the Treasury and the Federal Reserve Banks to motivate people who receive federal benefit checks (i.e., Social Security, Supplemental Security Income, etc.) to use direct deposit. A publication of the U.S. Department of the Treasury, Financial Management Service, that specifies procedures for ACH transactions originated on behalf of the Federal Government. The Green Book implements the requirements of Title 31, Code of Federal Regulations, Part 210, concerning government use of the ACH system. A mathematical calculation that creates a single number from critical fields in each transaction entry, as a validation against inadvertent alteration of data contents due to hardware failure or program error. ### I - L The Standard Entry Class code for International ACH Transaction. The number used in an ACH transaction by the Originator to identify the Receiver (e.g., account number with a biller, Social Security number). The account holder does not have sufficient funds to cover an item presented for payment. A credit or debit ACH entry that is part of a payment transaction involving a financial agency's office (i.e., depository financial institution or business issuing money orders) that is not located in the territorial jurisdiction of the United States. A debit entry initiated by an Originator pursuant to an authorization obtained from the Receiver via a secure Internet session. A WEB entry may also be a credit entry initiated by or on behalf of a consumer to a Consumer Account of a Receiver. A numeric day of the year. For example, January 12 has the Julian date of 012. Know Your Customer (or Client)—A term used to describe a set of money laundering control policies and procedures that are used to determine the true identity of a customer/client. An entry which creates a funds transfer as opposed to a prenotification or other zero-dollar item. Also referred to as a live dollar entry. A financial institution or Third-Party Processor service that facilitates rapid collection and posting of corporate receivables. Typically, customer payments are mailed to a lockbox or mailbox for collection, sorting, totaling and recording by the bank or provider rather than by the billing organization. ### M - O A credit or debit entry initiated at an electronic terminal as defined in Regulation E to affect a transfer of funds to or from a consumer account. The pre-printed bottom line of a paper check which contains the routing number of the drawee and the check number printed in machine-readable magnetic ink. Also referred to as Magnetic Ink Character Recognition Line. A mandatory field is necessary to ensure the proper routing and/or posting of an ACH entry. Any mandatory field not included in an ACH record will cause that entry, batch or file to be rejected by the ACH Operator before it ever gets sent to the Receiving Depository Financial Institution (RDFI). The Standard Entry Class code for Machine Transfer Entries (MTE). The national trade association for electronic payments, which establishes the rules, industry standards and procedures governing the exchange of commercial ACH payments by depository financial institutions. The ACH record format specifications described in the Nacha Operating Rules and Guidelines, which are the accepted and warranted payment format standards for payments delivered through the ACH Network. A TPS that has an origination agreement with another TPS to act on behalf of an Originator and does not have a direct origination agreement with the ODFI. A non-dollar entry sent to the Originating Depository Financial Institution (ODFI) by the Receiving Depository Financial Institution (RDFI) that contains information for the correction of erroneous information contained within an ACH entry. The agency of the United States Government concerned with monitoring and controlling the assets and financial transactions of entities deemed to be, or acting on behalf of, enemies of the United States. The term that refers to entries within an ACH file that belong to the Originating Depository Financial Institution (ODFI). These entries may be stripped from the file and posted internally before a file is sent to the ACH Operator. The risk that a transaction is altered or delayed due to unintentional error in transmission, receiving or processing. The inclusion or omission of an optional field is at the discretion of the Originator of an ACH transaction. While omission of optional fields will not affect the processing of the item, the Originator must still fill optional fields with blanks or other characters if they do not fill the field with actual information. The financial institution that delivers ACH entries directly or indirectly through a third party to its ACH Operator. The person or organization who has authorized an Originating Depository Financial Institution (ODFI) to transmit a credit or debit entry to the account of a Receiver with a Receiving Depository Financial Institution (RDFI), or if the Receiver is also the RDFI, to such Receiver. In some cases, the ODFI may also be the Originator. ### P - R A file listing prepared by Nacha of all financial institutions qualified to receive ACH entries. The directory is available from Accuity. Any financial institution that is authorized to originate/receive ACH entries. A communication system having the provisions to provide financial settlement information. A single-entry debit initiated by merchants for a purchase made in-person at the point-of-sale or a manned bill payment location, using the Receiver's check as a source document. An automated consumer payment format used for point-of-sale transactions originated in a non-shared system in which no agreement other than the ACH Rules exist between the Originating Depository Financial Institution (ODFI) and Receiving Depository Financial Institution (RDFI), and in which transactions generally are initiated by use of a merchant issued plastic card. The Standard Entry Class code used for the creation of Point-of-Purchase ACH entries. The Standard Entry Class code used for the creation of Point-of-Sale ACH entries. The Standard Entry Class code used for Prearranged Payment and Deposit ACH entries. An automated consumer payment application, usually in the context of a standing obligation, which credits or debits the consumer's account at their financial institution to satisfy that obligation. An optional, non-monetary entry that is sent through the ACH Network by an Originator to a Receiving Depository Financial Institution (RDFI) to verify account information. This "test" entry is sent prior to the live entry. The conditional settlement of debits and credits transferred via ACH. Until declared final by the Federal Reserve Bank, provisional settlement may be reversed. The Standard Entry Class code used for the creation of Re-presented Check Entries. Receiving Depository Financial Institutions (RDFI) - the financial institution that receives ACH entries from its ACH Operator and posts entries to Receivers' accounts. An individual, corporation or other entity that has authorized an Originator to initiate a credit or debit ACH entry to an account held at a Receiving Depository Financial Institution (RDFI). The ACH Operator which passes entries to the Receiving Depository Financial Institution (RDFI). The designated organization which receives ACH entries on behalf of a Receiving Depository Financial Institution (RDFI), whether the RDFI itself, a Third-Party Processor or a correspondent. Also referred to as a Third-Party Receiving Point. A procedure to recover benefit payments from a financial institution that were paid to that financial institution on behalf of a deceased or legally incapacitated beneficiary. A term that refers to information that is inscribed on a tangible medium or that is stored in an electronic or other medium and is retrievable in perceivable form. A payment that occurs at a regular interval for the same amount each time. An example of a recurring payment is a monthly loan or rent payment. A Notification of Change entry that has been returned to the Receiving Depository Financial Institution (RDFI) because of erroneous information contained within the original Notification of Change. Provides rules and guidelines for the efficient operation of the ACH Network. The regulation published by the Federal Reserve Board to implement the Electronic Funds Transfer Act mandating consumer rights and obligations with regard to electronic fund transfers. An entry which has been returned by the ACH Operator because it cannot be processed, usually because of a technical error in the entry, batch or file containing the entry. A replacement file generated upon request because an original file was unprocessable for some reason. A single-entry debit initiated for the purpose of collecting a paper check that has been returned for insufficient or uncollected funds. The omission of a required field will not cause rejection of an ACH entry at the ACH Operator level, but may cause rejection at the Receiving Depository Financial Institution (RDFI) level. An example of this is the omission of the Receiver's account number. Any ACH entries or files sent within required deadlines to "correct" or reverse previously originated duplicate or erroneous entries or files. The process of canceling a previously authorized ACH transaction. The revocation must be made directly with the Originator of the item in the manner specified in the original authorization form signed by the Receiver, and cannot be done via other parties such as the Receiving Depository Financial Institution (RDFI). A nine-digit number (eight digits plus a check digit) which identifies a specific financial institution. Routing numbers are administered by the Routing Number Administrative Board under the sponsorship of the American Bankers Association and officially maintained and published by Accuity. Also known as an ABA number. ### S - U The designated organization that sends ACH entries to the ACH Operator on behalf of an Originating Depository Financial Institution (ODFI), whether the ODFI itself, a Third-Party Processor or a correspondent. Also referred to as a Third-Party Sending Point. A transfer of funds between two parties in cash, negotiable items or on the books of a mutual depository to complete one or more prior transactions and made subject to final accounting. Settlement for the ACH Network occurs through the Federal Reserve Bank, with the exchange of funds occurring on settlement day. An account established by a financial institution, either directly with the Federal Reserve Bank or through a correspondent, for the funding of financial transactions. The date on which an exchange of funds with respect to an entry or entries is reflected on the books of the Federal Reserve Bank. An automated consumer payment format used for point-of-sale transactions within a shared network system in which the Originating Depository Financial Institution (ODFI) and Receiving Depository Financial Institution (RDFI) have a common operating agreement and in which the debit card is typically issued by the RDFI. Authentication of the Authorizing party by digital signature such as a unique PIN number. A three-character code within an ACH Company/Batch Header Record to identify the application type contained within an ACH entry that also determines the rules that apply to that entry (e.g., PPD, CCD, CTX, etc.). An advice prepared by the ACH Operator stating the number of items and dollar value of an ACH file. A directive by an account holder to its financial institution not to pay a particular ACH transaction or specific check. The possibility that one or more financial institutions will face losses (and/or go out of business) because of the inability of other financial institutions to settle their net debit obligations at the time of settlement. An identification number assigned by the Internal Revenue Service to taxpayers. The TIN for individuals is their Social Security number; for businesses it is their Employer Identification Number. An industry-wide convention (or agreement) for consistently formatting tax payment information carried in the addenda records attached to ACH tax payments. The TXP format for paying state and local taxes is slightly different from the IRS version. The Standard Entry Class code used for the creation of Telephone-Initiated Entries. A debit entry initiated by an Originator in accordance with the Receiver's oral authorization for the purchase of goods or services over the telephone. A third party that sends and/or receives ACH files on behalf of the Originator (e.g., payroll processor, bill payment provider). A third party that receives ACH files on behalf of the Receiving Depository Financial Institution (RDFI). Examples include correspondent banks, corporate credit unions and processors. Also referred to as a Receiving Point. Originating Depository Financial Institution (ODFI) customers to which Originators outsource payment services, but the ODFI has no direct customer or contractual relationship with the Originator. A Third-Party Sender provides services to the Originator, and, in that capacity, acts as an intermediary between the Originator and ODFI. A third party that sends ACH files on behalf of the Originating Depository Financial Institution (ODFI). Examples include correspondent banks, corporate credit unions and processors. Also referred to as a Sending Point. A third party that processes ACH files and/or entries on behalf of financial institutions and/or Originators. Third-Party Sending Points, Third-Party Receiving Points, Third-Party Processors and Third-Party Senders are subsets of Third-Party Service Providers. A standard ACH process that may be implemented by a state taxing authority to identify the tax payer when a third-party tax payer is involved in remitting the tax payment on behalf of the tax payer. A 15-digit code uniquely identifying each entry within a batch in an ACH file. The first eight digits of the trace number consists of the routing number (minus the check digit) of the Originating Depository Financial Institution (ODFI). The two-digit code in the ACH record that determines whether an entry is a debit or credit to a savings, demand deposit, FI general ledger account or a credit to a loan account. The transaction code also denotes whether the entry is a prenotification or live entry. The possibility that a loss will be sustained due to the incorrect transfer of funds. An example of this would be a transaction which would normally be processed as a wire transfer, with all of the normal associated security procedures for wire transfers, converting to an ACH transaction without having the same security procedures in place. The Standard Entry Class codes used for the creation of ACH entries from truncated checks. An ACH entry that originally represented a check in which the actual check is safekept by one of the financial institutions in the chain of deposit. The MICR information is then converted to an electronic entry and processed through the ACH Network back to the issuing institution. A series of TRC entries put together as addenda records with the payment item representing the total settlement of the TRC entries for that batch. The portion of the Uniform Commercial Code (UCC) which deals with certain funds transfers including ACH credit transactions not subject to the Electronic Funds Transfer Act or Regulation E. This law outlines the protections and responsibilities given to the parties to wholesale credit transactions and sets the legal standards for commercially reasonable security procedures to be used in conjunction with those transactions. A network, public or private, that is not located entirely within a single, contiguous, physical facility and any part of which that has not implemented security technologies that provide a commercially reasonable level of security that complies with applicable regulatory requirements. Unencrypted email and an unencrypted website are examples of an Unsecured Electronic Network. The Uniting and Strengthening America by Providing Appropriate Tools Required to Intercept and Obstruct Terrorism Act of 2001 was implemented in the aftermath of the events of September 11, 2001 and introduced a plethora of legislative changes which significantly increased the surveillance and investigative powers of law enforcement agencies in the United States. ### W - X The electronic storage of debit or credit transactions by a data processing system until their effective date. The Standard Entry Class code used for the creation of Internet-Initiated/Mobile Entries. Under the Uniform Commercial Code Article 4A, wholesale credit transactions are defined (roughly) as electronic credit transactions between commercial entities, such as businesses and their financial institutions. This term includes individual commercial ACH credit transactions and certain payment orders such as wire transfers and internal transfers, and as such, these transactions are subject to the provisions of Article 4A. An ACH file that is composed of individual consumer transactions is considered to be subject to UCC4A as well because, in the aggregate, the entire file is a transaction between a corporate entity and the Originating Depository Financial Institution (ODFI). A statement by a consumer declaring that a particular ACH transaction was unauthorized, improper or that authorization for the transaction had been revoked. The Standard Entry Class code used for the creation of Destroyed Check Entries. This appendix serves as a comprehensive reference for ACH processing terminology and procedures. Bookmark this page for quick access to definitions and explanations of ACH-related terms and concepts. # Create a Mastercard token for Straddle Source: https://docs.straddle.com/integrations/open-banking/mastercard Generate the Mastercard token required to create a Straddle paykey. Generate a Mastercard token for a checking account already connected through your Mastercard Open Finance integration. Mastercard's [Generate Third Party Access Key](https://developer.mastercard.com/open-finance-us/documentation/participant-model/partner-linked/client/client-steps/#operation/GenerateThirdPartyAccessKey) operation returns a consent receipt. Straddle calls the following three values from that receipt, taken together, a *Mastercard token*: * The receipt ID. * The returned customer ID. * The returned account ID. ## Before you begin Gather the following values for the environment you are using: * Your Mastercard app key, partner ID, and partner secret. * The Mastercard customer ID and account ID for the selected checking account. * Straddle's Mastercard partner ID for your environment. Sandbox and production use different IDs. See [Generate the Mastercard token](#generate-the-mastercard-token). Your Mastercard Open Finance partner account must be enabled for Partner Linked third-party access. Send all Mastercard requests from your server. Do not expose Mastercard credentials or tokens in a browser or mobile client. ## Authenticate with Mastercard Use Mastercard's [Create Access Token](https://developer.mastercard.com/open-finance-us/documentation/api-reference/#operation/CreateToken) operation to exchange your Mastercard partner ID and partner secret for a partner authentication token. ```bash Get a partner authentication token theme={null} curl --request POST \ --url https://api.finicity.com/aggregation/v2/partners/authentication \ --header "Finicity-App-Key: YOUR_MASTERCARD_APP_KEY" \ --header "Content-Type: application/json" \ --header "Accept: application/json" \ --data '{ "partnerId": "YOUR_MASTERCARD_PARTNER_ID", "partnerSecret": "YOUR_MASTERCARD_PARTNER_SECRET" }' ``` A successful request returns the partner authentication token in `token`. ```json Partner authentication response theme={null} { "token": "YOUR_MASTERCARD_PARTNER_AUTHENTICATION_TOKEN" } ``` Send this value in the `Finicity-App-Token` header when you create the Mastercard token. Partner authentication tokens are valid for two hours. Mastercard recommends replacing them after 90 minutes. ## Set the token scope Mastercard's [Generate Third Party Access Key](https://developer.mastercard.com/open-finance-us/documentation/api-reference/#operation/GenerateThirdPartyAccessKey) request sets two limits for each product in the consent receipt: * `accessPeriod` controls how long Straddle can use the product. * `maxCalls` controls how many times Straddle can request the product before Mastercard blocks further requests. Grant all three products for the same account. | Product | How Straddle uses it | | - | - | | `moneyTransferDetails` | Retrieves the routing number and account number during paykey creation. | | `accountOwner` | Retrieves account holder names during paykey creation. | | `availableBalanceLive` | Retrieves a balance during paykey creation and later charge balance checks or balance refreshes. | The request below sets `maxCalls` to Mastercard's example value of `200`. Paykey creation requests each product once. Later charge balance checks and balance refreshes can make additional `availableBalanceLive` requests. `200` is an example, not a published maximum. Confirm the supported limit for your Mastercard program if you need a different value. Set `maxCalls` and `accessPeriod` for every product. Set `accessPeriod.type` to `timeframe`, then replace the timestamps in the following request before sending it. ## Generate the Mastercard token In Mastercard's [Generate Third Party Access Key](https://developer.mastercard.com/open-finance-us/documentation/api-reference/#operation/GenerateThirdPartyAccessKey) request, set `partnerId` to your Mastercard partner ID. Set `thirdPartyPartnerId` to Straddle's Mastercard partner ID for the same environment. | Environment | Straddle's Mastercard partner ID | | - | - | | Sandbox | `2445585407443` | | Production | `2445585420093` | ```bash Generate a Mastercard token theme={null} curl --request POST \ --url https://api.finicity.com/aggregation/v1/partners/accessKey \ --header "Finicity-App-Key: YOUR_MASTERCARD_APP_KEY" \ --header "Finicity-App-Token: YOUR_MASTERCARD_PARTNER_AUTHENTICATION_TOKEN" \ --header "Content-Type: application/json" \ --header "Accept: application/json" \ --data '{ "customerId": "YOUR_MASTERCARD_CUSTOMER_ID", "partnerId": "YOUR_MASTERCARD_PARTNER_ID", "thirdPartyPartnerId": "STRADDLE_MASTERCARD_PARTNER_ID", "products": [ { "product": "moneyTransferDetails", "accountId": "YOUR_MASTERCARD_ACCOUNT_ID", "maxCalls": 200, "accessPeriod": { "type": "timeframe", "startTime": "START_TIME_UTC", "endTime": "END_TIME_UTC" } }, { "product": "accountOwner", "accountId": "YOUR_MASTERCARD_ACCOUNT_ID", "maxCalls": 200, "accessPeriod": { "type": "timeframe", "startTime": "START_TIME_UTC", "endTime": "END_TIME_UTC" } }, { "product": "availableBalanceLive", "accountId": "YOUR_MASTERCARD_ACCOUNT_ID", "maxCalls": 200, "accessPeriod": { "type": "timeframe", "startTime": "START_TIME_UTC", "endTime": "END_TIME_UTC" } } ] }' ``` Read `receiptId`, `customerId`, and `products[].accountId` from the response. ```json Consent receipt response theme={null} { "data": [ { "receipt": { "receiptId": "cr_4pfI2r1X8aOHrDDwrwC01NHTxOXlT1", "customerId": "3465230025077724000", "products": [ { "product": "moneyTransferDetails", "accountId": "4633415743960374024" }, { "product": "accountOwner", "accountId": "4633415743960374024" }, { "product": "availableBalanceLive", "accountId": "4633415743960374024" } ] } } ] } ``` ## Map the response to Straddle Map the fields in Mastercard's [Generate Third Party Access Key](https://developer.mastercard.com/open-finance-us/documentation/api-reference/#operation/GenerateThirdPartyAccessKey) response to the `mastercard` object in the Straddle Bridge request. | Straddle field | Mastercard response field | | - | - | | `mastercard.consent_receipt_id` | `data[].receipt.receiptId` | | `mastercard.customer_id` | `data[].receipt.customerId` | | `mastercard.account_id` | `data[].receipt.products[].accountId` | Confirm that the same returned account ID appears in all three product entries, then send that value as `mastercard.account_id`. Use the receipt ID and returned customer ID from that same consent receipt. Do not send Straddle the original customer or account IDs from the token request. Set the top-level `customer_id` in the Straddle request to the Straddle customer ID. `mastercard.customer_id` is the customer ID returned by Mastercard. Store `mastercard.consent_receipt_id`, `mastercard.customer_id`, and `mastercard.account_id` on your server with your record of the bank connection. ## Create the Straddle paykey Continue to [Create a paykey from a Mastercard token](/guides/bridge/mastercard-consent) after Mastercard returns the consent receipt. For Mastercard's complete Partner Linked procedure, see [Client steps](https://developer.mastercard.com/open-finance-us/documentation/participant-model/partner-linked/client/client-steps/). # Plaid integration for ACH payments Source: https://docs.straddle.com/integrations/open-banking/plaid Connect your existing Plaid integration to Straddle to convert Plaid Link bank connections into paykeys for ACH charges, payouts, and verification. Plaid Logo This guide provides a detailed walkthrough on integrating Plaid with Straddle for fast and secure account-to-account payments. By leveraging Plaid's bank connections and Straddle's payment infrastructure, you can offer a seamless and secure payment experience to your users. ## Prerequisites Before you begin, ensure you have: * [A Straddle account with API access](https://accounts.straddle.com/sign-up) * [A Plaid account with API access](https://my.plaid.com/sign-up/how-plaid-works) * Enable Straddle's Plaid integration in your Plaid [account settings](https://dashboard.plaid.com/team/integrations). If you need assistance with this step, reach out to your Account Manager with Plaid. * Customize Plaid Link's account selection to only be "[enabled for one account](https://dashboard.plaid.com/link/account-select)." ## Implementation steps Integrate Plaid Link into your frontend to allow users to securely connect their bank account. Plaid Link is the front-end module that facilitates the connection between the user's bank account and your application. Once the user connects their bank account using Plaid Link, Plaid returns a public token. Exchange this public token for an access token via Plaid’s API, which allows you to access the user's account information. With the access token obtained from Plaid, request a Straddle processor token from Plaid. This token allows you to link the user's bank account to Straddle's payment processing system. Pass the Straddle processor token to Straddle's Bridge API. Straddle returns a `paykey` which is linked to the user's bank account, allowing future transactions to be processed. Store the `paykey` securely in your system. Use this `paykey` to create charges, initiate payments, or perform other transactions via Straddle's API in the future. ## Setting up Plaid ### Configure Plaid product and Link settings in the Plaid dashboard To get the most out of the Straddle integration with Plaid, be sure to enable the following core services in your [Plaid dashboard](https://dashboard.plaid.com/settings/team/products). ![](https://unicorn-images.b-cdn.net/8305e162-9f09-4be7-9b66-5c9cbc026599?optimizer=gif\&width=1132\&height=686) Once that's complete, remember to style and customize your [Link application UI](https://dashboard.plaid.com/link). It's especially important to define a "use case" in the [Data Transparency Messaging](https://plaid.com/docs/link/data-transparency-messaging-migration-guide/) configuration. ![](https://unicorn-images.b-cdn.net/88480a8c-692f-493c-8624-c63caedfc6ab?optimizer=gif\&width=686\&height=896) Data transparency messaging ensures compliance with the latest open-banking regulations. Check out this article on [CFPB's 1033 Final Rule](https://plaid.com/resources/compliance/section-1033/) to learn more. ### Intro to Link Plaid Link is the client-side component that your users interact with to link their accounts to Plaid and allow you to access their accounts via the Plaid API. ![](https://plaid.com/_next/image?url=/assets/img/docs/docs-link-overview.png\&w=1920\&q=75) Plaid Link handles credential validation, multi-factor authentication, and error handling for each institution that Plaid supports. Link is supported via SDKs for all modern browsers and platforms, including [web](https://plaid.com/docs/link/web/), [iOS](https://plaid.com/docs/link/ios/), [Android](https://plaid.com/docs/link/android/), as well as via [React Native](https://plaid.com/docs/link/react-native/), along with community-supported wrappers for [Flutter](https://github.com/jorgefspereira/plaid_flutter), [Angular](https://github.com/mike-roberts/ngx-plaid-link), and [Vue](https://github.com/jclaessens97/vue-plaid-link/). For webview-based integrations or integrations that don't have a frontend, Plaid also provides a drop-in [Hosted Link](https://plaid.com/docs/link/hosted-link/) integration mode. To try Link, see [Plaid Link Demo](https://plaid.com/demo/). This guide gives you a rundown of the steps required to start building on Plaid and connect to Straddle. However, you should always treat [Plaid's official documentation](https://plaid.com/docs/link/#introduction-to-link) as the ultimate source of truth during integration with their platform. ### Create a `link_token` Now you're ready to start building. To integrate with Plaid Link, you first need to create a `link_token`. A `link_token` is a short-lived, one-time use token that is used to authenticate your app with Link and initiate a session for a user. To create one, make a [`/link/token/create`](https://plaid.com/docs/api/link/#linktokencreate) request with your `client_id`, `secret`, and a few other required parameters from your app server. View the [`/link/token/create`](https://plaid.com/docs/api/link/#linktokencreate) documentation for a full list of configurations. To see your `client_id` and `secret`, visit the [Plaid Dashboard](https://dashboard.plaid.com/developers/keys). ```bash theme={null} curl -X POST https://sandbox.plaid.com/link/token/create \ -H 'Content-Type: application/json' \ -d '{ "client_id": "${PLAID_CLIENT_ID}", "secret": "${PLAID_SECRET}", "client_name": "Plaid Test App", "user": { "client_user_id": "${UNIQUE_USER_ID}" }, "products": ["auth"], "country_codes": ["US"], "language": "en", "webhook": "https://webhook.example.com", "redirect_uri": "https://domainname.com/oauth-page.html" }' ``` ### Initialize Link Once you have a `link_token`, all it takes is a few lines of client-side JavaScript to [initialize Link](https://plaid.com/docs/link/#initializing-link). Then, in the `onSuccess` callback, you can call a simple server-side handler to exchange the Link `public_token` for a Plaid `access_token` and -- ultimately -- a Straddle `processor_token`. ```javascript theme={null} ``` ## Obtaining a Straddle processor token from Plaid Once you have the access token, you can use it to obtain a Straddle [processor token](https://plaid.com/docs/api/processors/#processortokencreate) from Plaid. This token is specific to Straddle and allows secure communication between Plaid and Straddle. ```javascript theme={null} # Exchange the public token from Plaid Link for an access token. curl \ -H 'Content-Type: application/json' \ -d '{ "client_id": "${PLAID_CLIENT_ID}", "secret": "${PLAID_SECRET}", "public_token": "${PUBLIC_TOKEN}" }' \ -X POST \ https://sandbox.plaid.com/item/public_token/exchange # Create a processor token for a specific account id. curl \ -H 'Content-Type: application/json' \ -d '{ "client_id": "${PLAID_CLIENT_ID}", "secret": "${PLAID_SECRET}", "access_token": "${ACCESS_TOKEN}", "account_id": "${ACCOUNT_ID}", "processor": "straddle" }' \ -X POST \ https://sandbox.plaid.com/processor/token/create ``` Note that `straddle` is the specific processor you're requesting the token for. This tells Plaid to generate a token compatible with Straddle's systems. ## Using the Straddle Bridge API with a Plaid token Once you have obtained the Straddle processor token from Plaid, you can use it to create a [paykey](/guides/bridge/paykeys) via Straddle's [Bridge API](/api-reference/bridge/plaid-token). Here's the correct HTTP request format: ```bash Bridge a Plaid Token theme={null} curl -X POST https://sandbox.straddle.com/v1/bridge/plaid \ -H "Authorization: Bearer YOUR_STRADDLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "plaid_token": "straddle-sandbox-123abc...", "metadata": { "nickname": "My Bank Account" } }' ``` Replace `YOUR_STRADDLE_API_KEY` with your actual Straddle API key, and fill in the appropriate values for `customer_id` and `plaid_token`. The `metadata` field is optional but can be useful for storing additional information related to the Plaid account. Straddle interacts with Plaid [/auth](https://plaid.com/docs/api/products/auth/) and [/identity](https://plaid.com/docs/api/products/identity/) endpoints on your behalf to resolve the user's bank account details and ownership information. ## Handling the Straddle API response The Straddle API responds with a paykey object. Here's an example of what you might receive: ```json theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******7890", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "CHASE BANK - *7890", "source": "plaid", "institution_name": "CHASE BANK", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z", "metadata": { "plaid_account_id": "5f7a8b9c0d1e2f3g4h5i6j7k" } }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ``` Note that the `source` field is set to `plaid` in this case, indicating that the paykey was created using a Plaid token. You should store this `paykey` securely for future use in transactions. When it's time to get paid, [create a charge](/api-reference/charges/create) and Straddle automatically attempts to verify the account's balance prior to origination. ## Best practices and security considerations 1. **Token Security**: Never expose Plaid access tokens or Straddle processor tokens to the frontend. Always handle these server-side. 2. **Error Handling**: Implement robust error handling for both Plaid and Straddle API calls. 3. **Metadata Usage**: Use the metadata field to store relevant information, such as the Plaid account ID, for future reference. 4. **Token Refreshing**: Be aware of token expiration policies for both Plaid and Straddle. Implement token refresh mechanisms as needed. 5. **Compliance**: Ensure you're complying with both Plaid and Straddle's terms of service and data handling requirements. 6. **Logging**: Implement comprehensive logging for debugging and audit purposes, but be careful not to log sensitive information. ## Troubleshooting common issues 1. **Invalid Processor Token**: Ensure you're using `straddle` as the processor when requesting the token from Plaid. 2. **Authentication Errors**: Double-check your API keys for both Plaid and Straddle. 3. **Expired Tokens**: If you're getting authentication errors, your tokens might have expired. Implement a token refresh mechanism. 4. **Account Not Supported**: Some bank accounts may not be supported for ACH transactions. Handle these cases gracefully in your UI. 5. **Rate Limiting**: Be aware of rate limits on both Plaid and Straddle APIs. Implement appropriate backoff strategies if you hit these limits. By following this guide, you should be able to successfully integrate Plaid with Straddle, leveraging the strengths of both platforms to provide a robust, secure payment solution for your users. # Quiltt integration for ACH payments Source: https://docs.straddle.com/integrations/open-banking/quiltt Connect your existing Quiltt integration to Straddle to convert Quiltt bank connections into paykeys for ACH charges, payouts, and account verification. Quiltt Logo This guide provides a detailed walkthrough on integrating Quiltt with Straddle for fast and secure account-to-account payments. By leveraging Quiltt's unified banking API and Straddle's payment infrastructure, you can offer a seamless and secure payment experience to your users. ## Prerequisites Before you begin, ensure you have: * [A Straddle account with API access](https://accounts.straddle.com/sign-up) * [A Quiltt account with API access](https://dashboard.quiltt.dev/) * Enable Straddle's Quiltt integration in your Quiltt account. If you need assistance with this step, reach out to your Account Manager with Quiltt. * Your Quiltt Connectors need to have access to `ACCOUNT_NUMBERS`, `ACCOUNT_BALANCE_REFRESHES` and `ACCOUNT_BALANCES_AND_TRANSACTIONS` features for Straddle to be able to fetch the needed information. In Sandbox, make sure that you are using a real connector sandbox environment, like MX or Finicity. ## Implementation steps Integrate Quiltt Connector into your frontend to allow users to securely connect their bank account. Quiltt Connector is the front-end module that facilitates the connection between the user's bank account and your application. Once the user connects their bank account using Quiltt Connector, Quiltt returns a Connection Id in a callback. Use the [GraphQL API](https://www.quiltt.dev/api/graphql) to fetch the Account Id from the Connection Id. With the Account ID obtained from Quiltt, request a Straddle processor token from Quiltt. This token allows you to link the user's bank account to Straddle's payment processing system. Pass the Straddle processor token to Straddle's Bridge API. Straddle returns a `paykey` which is linked to the user's bank account, allowing future transactions to be processed. Store the `paykey` securely in your system. Use this `paykey` to create charges, initiate payments, or perform other transactions via Straddle's API in the future. ## Setting up Quiltt ### Configure Quiltt product and Connector settings in the Quiltt dashboard To get the most out of the Straddle integration with Quiltt, be sure to enable the following features in your [Quiltt dashboard](https://dashboard.quiltt.dev/): 1. Navigate to your Connector configuration 2. Enable the following features: * **ACCOUNT\_NUMBERS** - Required for processor token generation * **ACCOUNT\_BALANCES\_AND\_TRANSACTIONS** - Required for Account Balance verification (Optional, but required for account balance verification when doing Charges) * **ACCOUNT\_BALANCE\_REFRESHES** - Required for account balance refresh (Optional, but required for account balance verification when doing Charges) * **ACCOUNT\_OWNERS** - For identity verification (Optional) Once that's complete, customize your Connector's appearance and branding to match your application's design. Set up your institution list to include the financial institutions most relevant to your users. Quiltt's unified API automatically handles data transparency and compliance requirements across multiple banking data providers. ### Intro to Connector Quiltt Connector is the client-side component that your users interact with to link their accounts to Quiltt and allow you to access their accounts via the Quiltt API. Quiltt Connector handles credential validation, multi-factor authentication, and error handling for each institution that Quiltt supports through its multi-provider network. Connector is supported via SDKs for all modern browsers and platforms, including [JavaScript](https://www.quiltt.dev/connector/javascript), [React](https://www.quiltt.dev/connector/sdk/react), [iOS](https://www.quiltt.dev/connector/sdk/ios), and [Android](https://www.quiltt.dev/connector/sdk/android). For webview-based integrations or integrations that don't have a frontend, Quiltt also provides URL-based integration options. To try Connector, visit the [Quiltt Dashboard](https://dashboard.quiltt.dev/). This guide gives you a rundown of the steps required to start building on Quiltt and connect to Straddle. However, you should always treat [Quiltt's official documentation](https://www.quiltt.dev/) as the ultimate source of truth during integration with their platform. ### Create a session token Now you're ready to start building. To integrate with Quiltt Connector, you first need to create a Session Token. A Session Token is a short-lived, one-time use token that is used to authenticate your app with Connector and initiate a session for a user. To create one, make a request to the Session API with your API credentials and user information from your app server. View the [Session Token documentation](https://www.quiltt.dev/authentication/issuing-session-tokens) for a full list of configurations. To see your API credentials, visit the [Quiltt Dashboard](https://dashboard.quiltt.dev/settings/api-keys). ```bash theme={null} curl -X POST https://auth.quiltt.io/v1/users/sessions \ -H 'Authorization: Bearer YOUR_API_KEY_SECRET' \ -H 'Content-Type: application/json' \ -d '{ "userId": "unique_user_id" }' ``` ### Initialize Connector Once you have a Session Token, all it takes is a few lines of client-side JavaScript to [initialize Connector](https://www.quiltt.dev/connector/javascript). Then, in the `onExitSuccess` callback, you can call a simple server-side handler to create a Straddle processor token. ```javascript theme={null} ``` For React applications, you can use the React SDK: ```javascript theme={null} import { useState } from 'react' import { QuilttButton } from '@quiltt/react' import type { ConnectorSDKCallbackMetadata } from '@quiltt/react' export const App = () => { const [connectionId, setConnectionId] = useState() const handleExitSuccess = (metadata: ConnectorSDKCallbackMetadata) => { setConnectionId(metadata?.connectionId) } return ( Add Account ) } export default App ``` ## Obtaining a Straddle processor token from Quiltt Once you have established a connection, you need to: 1. Fetch the account details using Quiltt's GraphQL API 2. Create a processor token for Straddle ```bash theme={null} # First, fetch accounts from the connection curl -X POST https://api.quiltt.io/v1/graphql \ -H 'Authorization: Bearer {SESSION_TOKEN}' \ -H 'Content-Type: application/json' \ -d '{ "query": "query GetAccount($connectionId: ID!) { connection(id: $connectionId) { accounts { type id } } }", "variables": { "connectionId": "conn_1305TogkohfDfjxY54VDbm" } }' # Then create a processor token for the selected account curl https://api.quiltt.io/v1/accounts/{ACCOUNT_ID}/processor_tokens \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {QUILTT_API_KEY}' \ --data '{ "processor": "STRADDLE", "issuer": "QUILTT" }' ``` Note that `STRADDLE` is the specific processor you're requesting the token for. This tells Quiltt to generate a token compatible with Straddle's systems. The `issuer` field should be set to `QUILTT`. ## Using the Straddle Bridge API with a Quiltt token Once you have obtained the Straddle processor token from Quiltt, you can use it to create a [paykey](/guides/bridge/paykeys) via Straddle's [Bridge API](/api-reference/bridge/quiltt-token). Here's the correct HTTP request format: ```bash Bridge a Quiltt Token theme={null} curl -X POST https://sandbox.straddle.com/v1/bridge/quiltt \ -H "Authorization: Bearer {YOUR_STRADDLE_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "quiltt_token": "processor-sandbox-123abc...", "metadata": { "nickname": "My Bank Account" } }' ``` Replace `YOUR_STRADDLE_API_KEY` with your actual Straddle API key, and fill in the appropriate values for `customer_id` and `quiltt_token`. The `metadata` field is optional but can be useful for storing additional information related to the Quiltt account. Straddle interacts with Quiltt's API on your behalf to resolve the user's bank account details and ownership information. ## Handling the Straddle API response The Straddle API responds with a paykey object. Here's an example of what you might receive: ```json theme={null} { "data": { "paykey": "05f5d55cb14f7e8a0ec2e5689376e3b4665efc34834d30995babbd5010b39913", "bank_data": { "routing_number": "011000138", "account_number": "******7890", "account_type": "checking" }, "id": "0191ef49-892c-7460-99d1-f5589d7d9989", "customer_id": "0191ef41-8de5-716c-bfa4-41cd79e85705", "label": "CHASE BANK - *7890", "source": "quiltt", "institution_name": "CHASE BANK", "status": "active", "created_at": "2024-09-14T06:47:39.5648743Z", "updated_at": "2024-09-14T06:47:39.5648746Z", "metadata": { "quiltt_connection_id": "conn_5f7a8b9c0d1e2f3g4h5i6j7k", "quiltt_account_id": "acc_1a2b3c4d5e6f7g8h9i0j" } }, "meta": { "api_request_id": "243431dd-7deb-4445-820d-55a942ace70f" }, "response_type": "object" } ``` Note that the `source` field is set to `quiltt` in this case, indicating that the paykey was created using a Quiltt token. You should store this `paykey` securely for future use in transactions. When it's time to get paid, [create a charge](/api-reference/charges/create) and Straddle automatically attempts to verify the account's balance prior to origination. ## Best practices and security considerations 1. **Token Security**: Never expose Quiltt API keys or Session tokens to the frontend. Always handle processor token creation server-side. 2. **Error Handling**: Implement robust error handling for both Quiltt and Straddle API calls. 3. **Metadata Usage**: Use the metadata field to store relevant information, such as the Quiltt connection and account IDs, for future reference. 4. **Token Refreshing**: Session tokens expire after a period of time. Implement token refresh mechanisms as needed. 5. **Compliance**: Ensure you're complying with both Quiltt and Straddle's terms of service and data handling requirements. 6. **Logging**: Implement comprehensive logging for debugging and audit purposes, but be careful not to log sensitive information. ## Troubleshooting common issues 1. **Invalid Processor Token**: Ensure you're using `straddle` as the processor when requesting the token from Quiltt. 2. **Authentication Errors**: Double-check your API keys for both Quiltt and Straddle. Remember that Quiltt uses Bearer authentication. 3. **Expired Tokens**: If you're getting authentication errors, your session tokens might have expired. Create a new session token for the user. 4. **Account Not Supported**: Some bank accounts may not be supported for ACH transactions. Handle these cases gracefully in your UI. 5. **Rate Limiting**: Be aware of rate limits on both Quiltt and Straddle APIs. Implement appropriate backoff strategies if you hit these limits. 6. **Missing Features**: If you can't create processor tokens, ensure your Quiltt Connector has the `ACCOUNT_NUMBERS` feature enabled. 7. **Connection Status**: Verify that the connection status is `active` before attempting to create processor tokens. By following this guide, you should be able to successfully integrate Quiltt with Straddle, leveraging the strengths of both platforms to provide a robust, secure payment solution for your users. # Integrations overview Source: https://docs.straddle.com/integrations/overview Connect your stack with Straddle. Browse available integrations for open banking providers, automation tools, and developer platforms like Plaid and Zapier. ## Coming soon # Zapier integration for Straddle webhooks Source: https://docs.straddle.com/integrations/webhooks/zapier Receive Straddle webhook events in Zapier to automate workflows, trigger notifications, and connect ACH payment activity to thousands of other apps. Zapier Logo This guide walks you through integrating **Zapier** with **Straddle** so that you can trigger automated workflows (Zaps) whenever events occur in Straddle, with no code required. ## Prerequisites Before you begin, make sure you have: * A **[Straddle account](https://dashboard.straddle.com/)** with access to the **Webhooks** section in the dashboard * A **[Zapier account](https://zapier.com/sign-up)** You need at least **Developer** level to see the **Webhooks** section in the Straddle dashboard. ## Implementation steps In Zapier, select **Create → Zaps**. Search for **“Straddle”** in the Trigger app list and select it. Zapier-Select-Trigger Zapier prompts you to **“Choose account” → “+ Connect a new account.”** Zapier-Connect-Account
Locate your **ApplicationId** and **IntegrationKey** in **Straddle Dashboard → Webhooks**, by selecting the **Get Zapier Integration Details** button. Zapier-Integration-Details
These credentials are generated **once**, so store them securely. If you rotate the key later, remember to update every Zap that uses it.
After authentication, Zapier lists the **available events** (e.g., *New Account*, *Charge Updated*). Select the one that best matches your workflow. Zapier-Event-Select Zapier fetches a recent sample event from Straddle so you can inspect the payload. Once you’re happy, select **Continue** and add **Action steps**: send a Slack message, create a record in Airtable, or kick off any of Zapier’s 6,000+ integrations.
## Best practices & security considerations 1. **Credential safety**: Store your **IntegrationKey** in a secure secret-management system. This is sensitive information. 2. **Key rotation**: If you regenerate the **IntegrationKey** in Straddle, update each created Zap to avoid broken triggers. 3. **Retries & idempotency**: Zapier automatically retries failed webhooks, but make sure your downstream systems can gracefully handle duplicate payloads. 4. **Logging**: Enable logging inside your Zap (via “Zap History”) to simplify debugging. ## Troubleshooting | Issue | Likely Cause | Resolution | | - | - | - | | **“401 Unauthorized”** in Zapier test | Incorrect **ApplicationId** or **IntegrationKey** | Re-copy the credentials from **Straddle Dashboard → Webhooks** | | No events appear during “Find Data” | The chosen event hasn’t occurred yet | Trigger the event in a test environment, or toggle **“Skip Test”** and finish setup | | Zap stops firing after key rotation | Old **IntegrationKey** still used | Update the key in **Zapier → My Apps → Straddle** | | Duplicate downstream records | Zap retries combined with non-idempotent Action | Deduplicate using a unique webhook `id` field or add a Filter step | For a deep dive into Straddle’s event schema, see the **[Webhooks API reference](/webhooks/overview/events)**. *** That’s it! By following these steps, you’ll have Straddle piping real-time events straight into Zapier, unlocking limitless automation possibilities across your entire stack. # Compare charge and payout volume Source: https://docs.straddle.com/playbooks/account-cash-flow Measure payment creation volume by day or seven-day period for a selected account. Compare the amounts and counts of charges and payouts created over a period. The report includes every stored payment status, including failed and canceled payments, so it describes payment creation volume. For money transferred to or from your bank account, use [reconciliation](/playbooks/reconcile-payments). ## Before you begin * Install the [Straddle CLI](/developer-tools/cli/install) and configure an API key for the environment you want to analyze. * Confirm your [integration type and acting account](/developer-tools/cli/auth-context). * Choose the number of days to include. The window ends today, using the local time zone of the computer running the CLI. * Keep the same context and database throughout. Add the same `--db PATH` to each `sync` and `cashflow` command if you use a custom database. ## Run the workflow ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. For SaaS or marketplace, select the account if needed and check again: ```bash theme={null} straddle use-account ACCOUNT_ID straddle agent-context --pretty ``` ```bash theme={null} straddle sync --resources payments --full --max-pages 0 --strict --json ``` Confirm a `sync_complete` event and a final `sync_summary` with `success: 1`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly` before drawing conclusions, including findings that accompany exit code zero. ```bash theme={null} straddle cashflow --days 30 --json ``` This produces one entry for today and each of the preceding 29 days. Days with no matching activity have zero counts and amounts. ```bash theme={null} straddle cashflow --days 90 --weekly --json ``` The weekly view combines consecutive seven-day periods starting on the first day of the requested window. The last period can contain fewer than seven days. Each entry's `date` is its first day. ## Interpret the results | Field | Meaning | | - | - | | `window_days` and `granularity` | Requested period and grouping, `day` or `week`. | | `total_in` and `total_out` | Total charge and payout amounts in the window, in cents. | | `net` | Charge amount minus payout amount, in cents. | | `buckets` | Periods containing `date`, `charge_count`, `charge_in`, `payout_count`, `payout_out`, and `net`. | Payments are grouped by `created_at`. Full timestamps are converted to the computer's local time zone; date-only values keep their recorded calendar day. Records with missing or unparseable creation dates are skipped. The calculation puts `payment_type: payout` in payout volume and treats other values, including unknown types, as charge volume. A value of `12500` represents \$125.00. A negative `net` means payout creation volume exceeds charge creation volume for that period. Check payment statuses and funding evidence before using the amount to explain an actual bank transfer. ## Complete the investigation Record the environment, acting account, refresh time, date window, time zone, and periods that need explanation. Use [local data investigation](/playbooks/investigate-data) to break the volume down by status, [failure and return investigation](/playbooks/returns) to inspect unsuccessful payments, or [reconciliation](/playbooks/reconcile-payments) to connect payments to funding events. # Find paykeys that need attention Source: https://docs.straddle.com/playbooks/expiring-paykeys Identify expired paykeys, upcoming expirations, and blocked paykeys eligible for unblocking. Find paykeys with an expiration date that needs attention or a block that may be recoverable. Use the results to identify affected customers and plan the required bank-connection follow-up. ## Before you begin * Install the [Straddle CLI](/developer-tools/cli/install) and configure an API key with access to the paykeys you want to inspect. * Confirm your [environment, integration type, and acting account](/developer-tools/cli/auth-context). * Keep that context and database throughout. For a custom database, add the same `--db PATH` to each `sync` and `expiring` command. For marketplace integrations, paykeys belong to the platform. These results cover platform-owned paykeys. The selected acting account identifies the local database context used throughout this workflow. ## Run the workflow ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. For SaaS or marketplace, select the account if needed and check again: ```bash theme={null} straddle use-account ACCOUNT_ID straddle agent-context --pretty ``` ```bash theme={null} straddle sync --resources paykeys --full --max-pages 0 --strict --json ``` Confirm a `sync_complete` event and a final `sync_summary` with `success: 1`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly` before using the list. Those findings can accompany exit code zero. ```bash theme={null} straddle expiring --days 14 --json ``` The report includes expired paykeys, paykeys with 14 or fewer whole days remaining, and other blocked paykeys marked eligible for unblocking. Change the positive `--days` value to use a different planning window. ```bash theme={null} straddle paykeys get PAYKEY_ID --data-source live --no-cache --json ``` Replace `PAYKEY_ID` with an `id` from the report. Check the current status, expiration date when present, customer association, and unblocking eligibility before choosing the follow-up. ## Interpret the results The result contains `window_days`, `count`, and a `paykeys` array. Each item's `reason` explains why it was included: | Reason | Meaning | | - | - | | `expired` | The recorded expiration date is in the past. | | `expiring` | The remaining whole days, rounded down, fall within the requested window. | | `blocked_recoverable` | The paykey has status `blocked` and `unblock_eligible: true`, and was not already included for expiration. | Items are ordered by those reasons, then by `days_to_expiry`. An expiration reason takes precedence when a paykey also has a recoverable block, so read `status` and `unblock_eligible` alongside `reason`. `expires_at` applies to certain paykeys. For an item included because of a block, interpret `days_to_expiry` only when it has a valid `expires_at`; a missing date can leave the numeric field at zero. Use the current paykey status to determine usability, including for paykeys outside this report's expiration and block criteria. ## Complete the investigation Record the paykey ID, customer ID, reason, and follow-up date. For expiration, identify the required bank-connection update for that customer's connection method. For a recoverable block, follow the prerequisites in the [paykey management guide](/guides/bridge/paykeys), including the customer's required bank approval before unblocking. Refresh the records after the update to confirm the result. # Review identity queue items Source: https://docs.straddle.com/playbooks/identity-review Find customers and paykeys in review and collect the details needed for a decision. Find customers and paykeys with a recorded status of `review`, then retrieve their review details. This workflow gives you the IDs and evidence to organize the next review action. ## Before you begin * Install the [Straddle CLI](/developer-tools/cli/install) and configure an API key with access to the customers and paykeys you want to review. * Confirm your [environment, integration type, and acting account](/developer-tools/cli/auth-context). * Keep that context and database throughout. For a custom database, add the same `--db PATH` to every `sync` and `review-queue` command. For marketplace integrations, customers and paykeys belong to the platform. These results cover platform-owned records. The selected acting account identifies the local database context used throughout this workflow. ## Run the workflow ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. For SaaS or marketplace, select the account if needed and check again: ```bash theme={null} straddle use-account ACCOUNT_ID straddle agent-context --pretty ``` ```bash theme={null} straddle sync --resources customers,paykeys --full --max-pages 0 --strict --json ``` Confirm that both resources emit `sync_complete` and that the final `sync_summary` has `success: 2`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly`, including those that accompany exit code zero, before treating the queue as complete. ```bash theme={null} straddle review-queue --json ``` To focus on customers: ```bash theme={null} straddle review-queue --type customers --json ``` Use `--type paykeys` for paykeys. The default, `all`, includes both kinds. For an item with `kind: customer`: ```bash theme={null} straddle customers review get-customer CUSTOMER_ID --data-source live --no-cache --json ``` For an item with `kind: paykey`: ```bash theme={null} straddle paykeys review get PAYKEY_ID --data-source live --no-cache --json ``` Replace the placeholder with the item's `id`. Use the returned review information to determine what evidence or decision the case needs. ## Interpret the results The report contains `count` and an `items` array. Each item includes: | Field | Meaning | | - | - | | `id` and `kind` | Customer or paykey to review. | | `status` | Stored status, `review`, used to select the item. | | `name` | Customer name, or the paykey label with institution name as a fallback, when present. | | `customer_id` | Related customer for a paykey, when present. | | `created_at` and `age_days` | Resource creation time and elapsed whole days since creation. An unknown creation time produces `age_days: -1`. | Items with known creation dates appear oldest first; unknown dates appear last. Use this ordering to locate older records. Review duration requires separate evidence of when the item entered `review`, because `age_days` measures the resource's age. An empty queue means the stored records in the selected context contain no matching statuses. If you expected a case, confirm the context, review the sync results, and retrieve that item's current review details. ## Complete the investigation Record the item ID, review findings, and the evidence or decision needed from the responsible reviewer. Use [customer identity guidance](/guides/identity/customers), [identity reasons](/guides/identity/reasons), and the [paykey guide](/guides/bridge/paykeys) to interpret the findings. After a decision, refresh the records and rerun the queue to confirm the updated state. # Investigate payment data Source: https://docs.straddle.com/playbooks/investigate-data Find local payment records with full-text search and answer aggregate questions with SQL. Answer a specific question about your payments using a refreshed local dataset. Use search to locate records by text, then use SQL for counts, amounts, or comparisons. ## Before you begin * Install the [Straddle CLI](/developer-tools/cli/install) and configure an API key for the resources you want to inspect. * Confirm your [environment, integration type, and acting account](/developer-tools/cli/auth-context). * Decide which records the question needs. The examples use payments; you can also synchronize customers, paykeys, or funding events for related questions. * Keep the same context and database throughout. Add the same `--db PATH` to each `sync`, `search`, and `sql` command if you use a custom database. ## Run the workflow ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. For SaaS or marketplace, select the account if needed and check again: ```bash theme={null} straddle use-account ACCOUNT_ID straddle agent-context --pretty ``` ```bash theme={null} straddle sync --resources payments --full --max-pages 0 --strict --json ``` Confirm a `sync_complete` event and a final `sync_summary` with `success: 1`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly`, including findings that accompany exit code zero, before treating the dataset as complete. To include related records, change the resource list to `payments,customers,paykeys,funding-events` and confirm completion for all four resources. In a marketplace integration, customer and paykey reads cover platform-owned records even when an acting account is selected. See [local data](/developer-tools/cli/local-data) for synchronization and storage details. Replace `SEARCH_TERM` with a word from the record you want to find: ```bash theme={null} straddle search "SEARCH_TERM" --type payments --data-source local --limit 20 --json ``` Search uses the local full-text index. The result contains a `results` array of matching records and `meta` describing the data source. The limit bounds the returned matches; use SQL for a complete count. ```bash theme={null} straddle sql "SELECT json_extract(data, '$.status') AS status, COUNT(*) AS payment_count, SUM(json_extract(data, '$.amount')) AS amount_cents FROM payments GROUP BY json_extract(data, '$.status') ORDER BY payment_count DESC" --json ``` This returns one row for each stored status, with its payment count and total amount in cents. It includes all stored dates in the selected context. To inspect the largest stored payments: ```bash theme={null} straddle sql "SELECT id, json_extract(data, '$.payment_type') AS payment_type, json_extract(data, '$.status') AS status, json_extract(data, '$.amount') AS amount_cents FROM payments ORDER BY amount_cents DESC LIMIT 10" --json ``` SQL runs a single read-only `SELECT` or `WITH` statement against the selected context. The original resource body is in the `data` JSON column. Use the payment type and ID from your results to retrieve the current details: ```bash theme={null} straddle charges get PAYMENT_ID --data-source live --no-cache --json ``` For a payout: ```bash theme={null} straddle payouts get PAYMENT_ID --data-source live --no-cache --json ``` ## Interpret the results Search returns matching resource objects under `results`; `meta.source` is `local` for the explicit local search above. SQL returns an array of row objects, with keys matching your selected column names or aliases. An amount of `12500` cents represents \$125.00. Both methods reflect the records stored for the selected API origin and acting account. A missing search match can result from the search terms, result limit, sync coverage, or account selection. Use a known record ID and a current API read to investigate a discrepancy, then refresh the local data as needed. When comparing totals, preserve the query's date, type, and status conditions. The example status summary adds charges and payouts together within each status; separate `payment_type` values when the direction matters to your question. ## Complete the investigation Save the query or search terms, relevant record IDs, environment, acting account, and refresh time with your findings. Continue with [reconciliation](/playbooks/reconcile-payments) for funding questions, [payment progress](/playbooks/payment-progress) for lifecycle questions, or [failure and return investigation](/playbooks/returns) for unsuccessful payments. # Payment operations playbooks Source: https://docs.straddle.com/playbooks/overview Investigate payment activity, funding, identity reviews, and paykeys with repeatable workflows. Choose a playbook for the question you need to answer. Each workflow identifies the records to collect, explains the result, and gives you a next step for the investigation. The workflows use the Straddle CLI to refresh local records and inspect current API details when needed. Start with [CLI installation](/developer-tools/cli/install) and [credentials and account context](/developer-tools/cli/auth-context). ## Choose a workflow Match payments to funding events and investigate missing funding details. Group payments by status and identify candidates for a cancellation review. Inspect failure reasons and find repeated failures associated with a paykey or customer. Find customers and paykeys in review and retrieve their review details. Identify expiration dates and blocked paykeys eligible for unblocking. Compare payment creation volume by day or seven-day period. Search local records or use SQL to answer a specific question. ## Work from a consistent set of records Each playbook begins by confirming the environment and acting account, then refreshing the resources it needs. Keep that context and the same local database throughout the workflow. See [local data](/developer-tools/cli/local-data) for synchronization and storage details. Before acting on a record, retrieve its current API details as shown in the playbook. Record the relevant IDs, account, environment, and refresh time with your findings so another person can continue the investigation. # Check payment progress Source: https://docs.straddle.com/playbooks/payment-progress Group charges and payouts by status and inspect payments that may still be canceled. Find where payments are in their lifecycle and identify the records that need attention. This workflow produces counts and amounts by status, plus a list of payments whose stored status is eligible for a cancellation review. ## Before you begin * Install the [Straddle CLI](/developer-tools/cli/install) and configure an API key for the environment you want to inspect. * Confirm your [integration type and acting account](/developer-tools/cli/auth-context). SaaS and marketplace integrations select the account being investigated. * Use the same environment, acting account, and database throughout. For a custom database, add the same `--db PATH` to each `sync` and `pipeline` command. ## Run the workflow ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. The environment is the API origin. Direct account integrations show a `null` acting account. For SaaS or marketplace, select the account if needed, then check the context again: ```bash theme={null} straddle use-account ACCOUNT_ID straddle agent-context --pretty ``` ```bash theme={null} straddle sync --resources payments --full --max-pages 0 --strict --json ``` This fetches charges and payouts from the start of the resource, without the default page limit. Confirm a `sync_complete` event and a final `sync_summary` with `success: 1`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly` before relying on the report; those findings can accompany exit code zero. ```bash theme={null} straddle pipeline --json ``` The report groups all stored payments in the selected context by status. To list the individual cancellation candidates: ```bash theme={null} straddle pipeline --cancelable --json ``` Use the candidate's `type` to choose the command. Replace `PAYMENT_ID` with its `id`. ```bash theme={null} straddle charges get PAYMENT_ID --data-source live --no-cache --json ``` For a payout: ```bash theme={null} straddle payouts get PAYMENT_ID --data-source live --no-cache --json ``` Review the current status and status details before deciding how to handle the payment. ## Interpret the results | Field | Meaning | | - | - | | `by_status` | Status groups sorted alphabetically. Each contains `status`, `count`, `total`, and `cancelable`. | | `total` | Sum of full payment amounts in the group, in cents. Charges and payouts are added together. | | `cancelable_count` and `cancelable_total` | Count and total amount of payments stored as `created`, `scheduled`, or `on_hold`. | | `cancelable` | Whether the stored status is one of those three candidate statuses. | The `--cancelable` result is an array of payments with `id`, `type`, `status`, `amount`, and `cancelable`. A value of `12500` in an amount field represents \$125.00. Cancellation candidates are selected from stored statuses. A payment may have progressed since synchronization. Its current status, hold details, and the permissions of your API key determine the action available when you make the request. ## Complete the investigation Use the [payment status guide](/guides/payments/statuses) to interpret the current state. Record the payment ID and the action or follow-up it requires. For `failed` or `reversed` payments, continue with [failure and return investigation](/playbooks/returns). For funding questions, [reconcile the payment](/playbooks/reconcile-payments). # Reconcile payments Source: https://docs.straddle.com/playbooks/reconcile-payments Match charges and payouts to funding events, then investigate payments with missing funding details. Find the payments associated with a funding event and identify payments that still need investigation. This playbook produces a list of payment IDs, their recorded statuses and amounts, and their links to funding events. A [funding event](/guides/payments/funding) records money moving between Straddle and your linked bank account. Use its ID to connect the payments in your application with the corresponding bank activity. ## Before you begin Prepare the following: * Install the [Straddle CLI](/developer-tools/cli/install). * Configure an API key for the environment you want to review. Use sandbox for test data and production for actual payment activity. * Confirm your [integration type and acting account](/developer-tools/cli/auth-context). SaaS and marketplace integrations select the account being reconciled. * Have the funding event ID available if you're investigating a specific transfer. The commands use the CLI's configured environment and acting account. Keep that context throughout the workflow. If you use a custom database, add the same `--db PATH` to every `sync` and `reconcile` command. ## Run the workflow Use the Straddle CLI to download payment and funding records, group them, and inspect any gaps. Inspect the resolved context: ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. The environment is the API origin, such as `https://sandbox.straddle.com`. Direct account integrations show a `null` acting account. For a SaaS or marketplace integration, select the account before continuing: ```bash theme={null} straddle use-account ACCOUNT_ID ``` Run `agent-context` again after changing the selection. The local store separates records by API origin and acting account, so changing either selection changes which records reconciliation reads. Download both sets of records into the local store: ```bash theme={null} straddle sync --resources payments,funding-events --full --max-pages 0 --strict --json ``` The `payments` resource includes charges and payouts. `--full` starts from the beginning of each resource, and `--max-pages 0` removes the default 100-page limit. This can take longer for accounts with a large payment history. Sync updates the local records it fetches. The command prints one JSON event per line. Confirm that both resources emit `sync_complete` and that the final `sync_summary` reports `success: 2`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly` events before using the results. `--strict` makes resource errors fail the command. Access warnings and some data anomalies can still leave the command with exit code zero. Resolve those findings and repeat the sync before treating the local records as complete. Generate the reconciliation report: ```bash theme={null} straddle reconcile --json ``` The report contains `funding_events`, an array of payment groups, and `outstanding`, the payments without a funding reference. It reads the local records refreshed in the preceding step. To focus on one transfer, replace `FUNDING_EVENT_ID` with its ID: ```bash theme={null} straddle reconcile --funding-event FUNDING_EVENT_ID --json ``` This returns one group with its funding amount, payment count, payment total, and payment list. List the payments that need a closer look: ```bash theme={null} straddle reconcile --outstanding --json ``` Read each payment's `status` alongside its ID and amount. The `outstanding` label means the stored payment has no `funding_id` or nonempty `funding_ids` entry. The list can include payments at different stages, including failed or cancelled payments. ## Interpret the results Use the following fields to investigate a funding event: | Field | Meaning | | - | - | | `funding_event_id` | Funding event referenced by the grouped payments. | | `status` and `direction` | Values from the stored funding event, when available. | | `funding_amount` | Amount from the stored funding event, in cents. | | `payment_count` | Number of stored payments that reference this event. | | `payment_total` | Sum of those payments' full amounts, in cents. | | `payments` | Matching payments, each with `id`, `type`, `status`, and `amount`. | For the outstanding view, the result contains `payment_count`, `payment_total`, and `payments`. A value of `12500` represents \$125.00. Funding references establish which records are linked. Read the payment and funding event statuses to determine their processing state. A payment linked to several events appears in each group with its full amount, so adding group totals can count the same payment more than once. Compare `payment_total` and `funding_amount` within the event you're investigating; the report leaves that comparison to you. If `status` and `direction` are absent and `funding_amount` is zero, the local store may be missing the funding event. Fetch its current details before interpreting that zero as an actual amount: ```bash theme={null} straddle funding-events get FUNDING_EVENT_ID --data-source live --no-cache --json ``` For an empty or incomplete payment group, compare the local result with the API's payment search: ```bash theme={null} straddle payments --funding-id FUNDING_EVENT_ID --all --data-source live --no-cache --json ``` The full reconciliation view includes events referenced by stored payments. A specific-event lookup can return an empty group even when the ID has no local record. Use the live reads to establish whether the event exists and which payments the API returns for it, then refresh the local records. ## Complete the investigation Match the funding event's amount and transfer details to your bank activity using the [funding and reconciliation guide](/guides/payments/funding). Record the funding event ID, related payment IDs, environment, acting account, and when you refreshed the data. For payments still requiring investigation, use their recorded status to choose the next step: check processing and funding timing, inspect failure or return details, or correct the account selection and refresh. Keep unresolved differences attached to those IDs so the next review starts with the same records. # Investigate failed and returned payments Source: https://docs.straddle.com/playbooks/returns Find failed or reversed payments, inspect their reasons, and identify repeated failures. Identify payments with a recorded status of `failed` or `reversed`, then inspect the reason for each result. You can also group repeated failures by paykey or customer to prioritize follow-up. ## Before you begin * Install the [Straddle CLI](/developer-tools/cli/install) and configure an API key for the environment you want to inspect. * Confirm your [integration type and acting account](/developer-tools/cli/auth-context). * Choose a payment creation window. The report's `--days` filter uses the payment's `created_at`, rather than the date it failed or was returned. * Keep the same context and database throughout. Add the same `--db PATH` to each `sync` and `returns` command if you use a custom database. ## Run the workflow ```bash theme={null} straddle agent-context --pretty ``` Check `runtime_context.environment`, `runtime_context.integration_type`, and `runtime_context.acting_account`. For SaaS or marketplace, select the account if needed and check again: ```bash theme={null} straddle use-account ACCOUNT_ID straddle agent-context --pretty ``` ```bash theme={null} straddle sync --resources payments --full --max-pages 0 --strict --json ``` Confirm a `sync_complete` event and a final `sync_summary` with `success: 1`, `warned: 0`, and `errored: 0`. Review any `sync_warning` or `sync_anomaly` before using the results. Exit code zero can accompany those findings. Inspect payments created within the past 30 days: ```bash theme={null} straddle returns --days 30 --json ``` Use `--days 0` to include all stored history. Records with missing or unparseable creation dates remain in the result and sort after records with known dates. To identify repeated failures over a wider creation window: ```bash theme={null} straddle returns --days 90 --repeat-offenders --json ``` Retrieve a charge from the result: ```bash theme={null} straddle charges get PAYMENT_ID --data-source live --no-cache --json ``` For a result with `type: payout`, use: ```bash theme={null} straddle payouts get PAYMENT_ID --data-source live --no-cache --json ``` Inspect its current status and `status_details` before deciding on customer follow-up or another payment attempt. ## Interpret the results The standard report contains `window_days`, `count`, `total`, and a `returns` array when matches exist. `count` includes both failed and reversed payments. `total` is their summed amount in cents. | Payment field | Meaning | | - | - | | `id`, `type`, and `status` | Payment to investigate and its recorded state. | | `code` | Stored `status_details.code`, when present. Read the code and reason together to identify the failure. | | `reason` | Stored `status_details.reason`, falling back to `status_details.message`. | | `paykey` and `customer_id` | Related payment method and customer, when available. | | `created_at` | Payment creation time used for the window and newest-first ordering. | With `--repeat-offenders`, the report includes an `offenders` array when repeated-failure groups exist. Each group has more than one matching payment. The CLI groups by paykey, or by customer ID when the paykey is absent. Payments without either identifier contribute to the overall count and total but cannot form a group. Groups are ranked by their `returns` count, then `total` amount. The report's top-level count and total cover all matching failed and reversed payments, including those outside the repeated-failure groups. Each amount is in cents: `12500` represents \$125.00. ## Complete the investigation Record the payment ID, current reason, related paykey or customer, and required follow-up. Use the [payment status guide](/guides/payments/statuses) to interpret the state. If the issue affects a funding transfer, continue with [reconciliation](/playbooks/reconcile-payments). If the paykey is blocked, [inspect paykeys that need attention](/playbooks/expiring-paykeys). # Webhooks 101 Source: https://docs.straddle.com/webhooks/overview/101 Learn the basics of deploying webhook endpoints, ingesting Straddle event payloads, and verifying signatures so your platform reacts to ACH events reliably. The Straddle APIs utilize webhooks to notify you in real-time when certain events occur within your platform or account. At their core, webhooks are simply **HTTP POST** requests to a pre-configured endpoint that you control. ## How webhooks work 1. **Event Occurs**: A relevant event happens within the Straddle platform (e.g., a customer makes a payment). 2. **Webhook Sent**: Straddle sends a POST request to your designated endpoint with a JSON payload describing the event. 3. **Your Response**: To indicate successful processing, return a **2xx** (200–299) HTTP status code within 15 seconds. This assures Straddle you’ve received the event and prevents unnecessary retries. Make sure to disable CSRF protection on your webhook endpoint if your framework has it enabled by default. ### Why verify? To ensure that the webhook you receive is indeed from Straddle and not from a malicious source, it’s important to: * **Verify the Signature**: Check the cryptographic signature attached to the event. * **Verify the Timestamp**: Validate the event’s timestamp to prevent replay attacks. See the [Why Verify Webhooks](/webhooks/security/why-verify) section for more details. ## Key concepts at a glance Ensure authenticity by verifying signatures and timestamps. Respond with a 2xx status code within 15s to confirm receipt. Subscribe only to the events you need to reduce noise. Easily replay events from the dashboard if something goes wrong. ## Dashboard console The Straddle Dashboard provides a comprehensive **webhook console** for managing your webhook integration: * **Configure Endpoints**: Add or edit endpoints that receive webhooks. * **Select Event Types**: Subscribe to the events that matter to you. * **Monitor Deliveries & History**: View timestamps, statuses, and payload data of past deliveries. * **Inspect Payloads**: Examine each event’s payload to assist in debugging. * **Retry & Replay**: Manually resend events that may have failed. * **Activity Tracking**: Understand what happened and when. ## Get started quickly Set up endpoints and configure event types right from the dashboard. Use Svix Play or the built-in debugger to simulate events before going live. Implement signature and timestamp checks to ensure payload integrity. Once tested, deploy your endpoint and start receiving real-time events. While the dashboard is the quickest way to get started, you can also use the Straddle API to build custom webhook management workflows tailored to your environment. With these fundamentals in place, you’re ready to confidently integrate and handle webhooks from Straddle. # Configure webhook endpoints Source: https://docs.straddle.com/webhooks/overview/endpoints Configure webhook endpoints in the Straddle dashboard, subscribe to event types, and test deliveries to start receiving real-time ACH payment notifications. To start receiving messages (webhooks) from Straddle, you’ll first need to configure your endpoints in the Straddle dashboard. ## Getting started 1. Navigate to the **"Webhooks"** section in your **"Developers"** menu. 2. Add an endpoint by providing a URL that you control and selecting the event types you want to listen to. ## Svix x Straddle Straddle has partnered with [Svix](https://www.svix.com) to enable instant testing and debugging of Straddle webhooks. * **No URL yet?** If your service isn't ready or you don’t have a URL, select the **"Use Svix Play"** button to generate a unique test URL. * You’ll be able to view and inspect all webhooks sent to your Svix Play URL, making it easy to get started before your own endpoint is live. When configuring your endpoint, make sure to review the **Event Catalog** for full descriptions of each event type and the fields they include. If you don't specify any event types, your endpoint receives **all events**, which can be useful for testing. However, once you’re ready for production, Straddle recommends restricting the event types to those you actually need. ## Integration tips ### Use the built-in Svix debugger When first starting out, Straddle recommends using the built-in Svix debugger. This allows you to trigger generated (fake) event bodies to your specified URL on command. It’s perfect for: * Quickly understanding the JSON structure of events. * Iterating on your handling logic before going live. Since these events are fake, all IDs and URLs within them are inaccessible and do not map to real resources. ### Local development with ngrok When you’re ready to move on to local development, Straddle recommends using a tunneling tool like **ngrok**. Ngrok makes it possible for Straddle to reach your locally running web server without you needing to deploy it. This setup allows you to develop and test your webhook handling logic in real-time. ## Receiving webhooks To receive webhooks from Straddle: * Create a new endpoint on your web server that accepts **POST** requests with `Content-Type: application/json`. * Ensure this endpoint is accessible by Straddle (avoid firewalls or IP restrictions that would block requests). * When Straddle sends you a webhook, respond with a **2xx** status code to confirm receipt. Straddle considers any other status code (or lack thereof) a failure and retries delivery. If your webhook endpoint does additional processing, you can return 2xx immediately and then perform the logic afterward. This prevents unnecessary retries caused by slow or complex processing steps. Any information you return in the response is recorded and visible in the Straddle Dashboard logs. Although Straddle won’t process this data, it can be useful for debugging. Straddle recommends returning a concise JSON object with any helpful info. Straddle sends webhook events as soon as they become available. While typically fast, real-time guarantees are not provided, and occasional delays may occur. ## Testing endpoints Before going live, you can validate your integration by testing endpoints in the dashboard: 1. Navigate to the **Testing** tab in your webhook console. 2. Select an event type to test. 3. Send an example payload to your endpoint. 4. Watch the delivery attempt in real-time, inspect the full message details, and view logs. This immediate feedback loop helps you catch configuration issues early, ensuring that your endpoint can properly handle events before moving into production. # Webhook event catalog Source: https://docs.straddle.com/webhooks/overview/events A comprehensive catalog of webhook events available on the Straddle platform, including charge, payout, customer, and account lifecycle event payloads. # Event Catalog ## Overview Webhooks notify you when important events occur in the Straddle platform. This catalog details all available events and their payloads. You can browse the complete event catalog in your [Straddle Dashboard](https://dashboard.straddle.com) or reference the [full object documentation](https://strddl.co/webhooks). ## Event categories Monitor the lifecycle of embedded client accounts in your platform Monitor the lifecycle of Linked Bank Accounts for embedded client accounts in your platform Monitor the lifecycle of Representatives for embedded client accounts in your platform Monitor the lifecycle of CapabilityRequests for embedded client accounts in your platform Track charges and payouts through Straddle's multi-rail payment network Stay updated on customer verification and Paykey status changes ## Accounts events Account events are specifically relevant for platforms using Straddle's embedded payments functionality. They help you monitor the lifecycle and status changes of accounts you manage. These events are not relevant for businesses building on Straddle directly. | Event | Description | | - | - | | `account.created.v1` | Fired when a new embedded Straddle account is created. This event includes the account details, business profile, and its initial capabilities and status. | | `account.event.v1` | Triggered when any significant change occurs to an embedded account’s status or configuration. This includes verification updates, capability changes, and settings adjustments. | ## LinkedBankAccount events LinkedBankAccount events are specifically relevant for platforms using Straddle's embedded payments functionality. They help you monitor the lifecycle and status changes of accounts you manage. These events are not relevant for businesses building on Straddle directly. | Event | Description | | - | - | | `linked_bank_account.created.v1` | Fired when a platform creates a new embedded merchant account's LinkedBankAccount. This event contains the LinkedBankAccount details. | | `linked_bank_account.event.v1` | Triggered when any significant change occurs to a platform-created embedded account's linked bank account. This includes updates to the linked bank account status or values. | ## Representative events Representative events are specifically relevant for platforms using Straddle's embedded payments functionality. They help you monitor the lifecycle and status changes of accounts you manage. These events are not relevant for businesses building on Straddle directly. | Event | Description | | - | - | | `representative.created.v1` | Fired when a platform creates a new embedded merchant account's representative. This event contains the representative details. | | `representative.event.v1` | Triggered when any significant change occurs to a platform-created embedded account's representatives. This includes updates to the representative status or values. | ## CapabilityRequest events CapabilityRequest events are specifically relevant for platforms using Straddle's embedded payments functionality. They help you monitor the lifecycle and status changes of accounts you manage. These events are not relevant for businesses building on Straddle directly. | Event | Description | | - | - | | `capability_request.created.v1` | Fired when a platform creates a new embedded merchant account's CapabilityRequest. This event contains the CapabilityRequest details. | | `capability_request.event.v1` | Triggered when any significant change occurs to a platform-created embedded account's capability request. This includes updates to the capability request status or values. | ## Payments Payment events encompass money movements, including charges (incoming funds) and payouts (outgoing funds). They provide real-time updates on transaction processing, fraud screening, settlement status, and more. | Event | Description | | - | - | | `charge.created.v1` | Fired when a new charge is initiated. Includes details about the charge, the associated Paykey and bank account, and the initial payment status. | | `charge.event.v1` | Triggered throughout the charge lifecycle to indicate status changes and key updates—such as successful processing, failures, fraud detections, and settlement status. | | `payout.created.v1` | Fired when a new payout is initiated to send funds to a customer’s bank account. Includes amount, destination bank details, selected payment rail, and initial status. | | `payout.event.v1` | Triggered throughout the payout lifecycle. Indicates status changes, processing steps, failures, rail optimizations, and final settlement outcomes. | *** ## Customers Customer and Paykey events center around the core components of payment authorization. Customers represent the payers, while Paykeys link verified customers to their funding sources, ensuring secure and compliant transactions. | Event | Description | | - | - | | `customer.created.v1` | Fired when a new customer is created. Includes customer profile details, verification status, and the initial compliance screening outcome. | | `customer.event.v1` | Triggered when a customer’s profile or status changes. This may include verification updates, compliance checks, risk rating changes, or modifications to customer data. | | `paykey.created.v1` | Fired when a new Paykey is generated to link a customer to their bank account. Includes tokenized details, verification status, and initial fraud screening results. | | `paykey.event.v1` | Triggered when important updates occur to a Paykey’s status or associated bank account. This may include verification changes, fraud alerts, or usage permission modifications. | *** Use these events to build reactive, secure, and informed applications. By subscribing to the relevant events, you can automate downstream actions such as updating internal records, sending notifications to customers, or initiating additional compliance checks. Subscribe to both `created` and `event` webhook types for each resource to ensure you receive comprehensive updates about your integration. # Filter webhook delivery logs Source: https://docs.straddle.com/webhooks/overview/filtering Locate and filter webhook delivery logs in the Straddle dashboard to debug specific messages, find failed events, and inspect individual delivery payloads. When you need to track down a particular message that was sent to one of your endpoints, Straddle provides filtering options to help you quickly locate the information you need. ## Endpoint-level filtering If you know the endpoint that the message was delivered to: 1. Go to the endpoint's details page. 2. You see a filtered list of all messages sent to that endpoint. 3. Use the **Event Type** filter to show only messages of a specific event type. ## Date and time filters If you have an approximate timeframe in mind: * Narrow down your search by applying a **Date Filter** to the endpoint's message list. * This helps you focus on messages sent during a particular time window. ## Global logs filtering If you're unsure which endpoint received the message or if you have multiple endpoints: 1. Navigate to the **"Logs"** tab in your console. 2. Use the global filtering and search functionality to narrow down your query. 3. By applying filters (such as event type, endpoint, or date range), you can quickly locate the specific message you're looking for. These filtering options make it easy to trace and troubleshoot events, ensuring you can pinpoint and address issues with minimal effort. # Polling Endpoints Source: https://docs.straddle.com/webhooks/overview/polling Use the Straddle event polling endpoints to fetch a stream of recent ACH payment events on demand, without setting up a public webhook endpoint. In addition to receiving webhooks to your HTTP endpoints or connected applications like Slack, you can now also poll an endpoint to get all of the events in real-time and a consistent order. ## Why use polling? While webhooks are a great way to receive notification of events, there are situations where polling for events is preferred. For example, when testing locally it's much easier to poll for events than exposing a public HTTP endpoint. Another example is if you don't care about getting certain events in real-time and prefer getting them in a batch at the end of the day. In that case, you can use the polling endpoint to ingest event history when you're ready. **Both is good** Consider combining webhooks (pushing) and polling (pulling). You can, for example, use a webhook to act as a trigger to fetch from the polling endpoint. Or use the polling endpoint(s) periodically throughout the day to always have your events streamed in a first-in-first-out order (which is [difficult to guarantee with webhooks](https://www.svix.com/blog/guaranteeing-webhook-ordering/).) ## Create a polling endpoint Start by creating an endpoint from the Webhooks page in your Straddle dashboard. This time, select *Polling Endpoint* as the type. As with [regular webhook endpoints](https://docs.straddle.com/webhooks/overview/events), you can control which event types and channels you want to receive. ## Usage Once you've created a Polling Endpoint, you'll get a unique URL like [`https://api.svix.com/api/v1/app/app_2mG6DgUaGlwCNdM5oRCUJec2kQC/poller/poll_59q`](https://api.svix.com/api/v1/app/app_2mG6DgUaGlwCNdM5oRCUJec2kQC/poller/poll_59q) You can call this endpoint directly once you have a polling API Key. ```curl theme={null} -X GET "https://api.us.svix.com/api/v1/app/app_2o7jxcJHDH7Abg52iKsURWPmcEe/poller/poll_o3h" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer sk_poll_*****.eu' ``` When you first call the endpoint, it returns an empty array and an iterator. ```json theme={null} { "data": [], "iterator": "eyJvZmZzZXQiOi05MjIzMzcyMDM2ODU0Nzc1ODA4LCJhZnRlciI6bnVsbH0", "done": false } ``` Then, using the iterator in the next call, you can iterate through the events and poll for new ones. ```curl theme={null} -X GET "https://api.us.svix.com/api/v1/app/app_2o7jxcJHDH7Abg52iKsURWPmcEe/poller/poll_o3h?iterator=eyJv..." \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer sk_poll_*****.eu' ``` ## API keys To call the Polling Endpoint, you'll need to create an endpoint-specific API key. Be sure to store this in a secure environment! This API Key is only used to authenticate with the specific polling endpoint and is distinct from your Straddle-wide API keys. # Webhook replays and retries Source: https://docs.straddle.com/webhooks/overview/replays Learn how Straddle retries failed webhook deliveries, replays past events from the dashboard, and recovers when your endpoint returns errors or is offline. ## Replays Occasionally, a change or issue in your internal environment may cause webhook deliveries to fail. Replays help you address scenarios like: * **Service Downtime**: If your service was down and missed events. * **Endpoint Misconfiguration**: If you had the wrong endpoint configured. ### Replaying a single event If you want to replay a single event, you can find the message from the console and select the options menu next to any of the attempts. From there, select **"Resend"** to send the same message to your endpoint again. ### Bulk recovery If you need to recover from a service outage and replay all events since a given time, you can do so from the Endpoint page: 1. Go to the endpoint's details page. 2. Select **Options > Recover Failed Messages**. 3. Select the broader time window from which you want to recover. For more granular recovery, such as when you know the exact timestamp you want to recover from, select the options menu on any message from the endpoint page. Then select **"Replay..."**, followed by **"Replay all failed messages since this time."** ## Retry policy When Straddle attempts to deliver a webhook and fails to get a successful response (2xx status code), it keeps trying to deliver the same event using an exponential backoff schedule. This gives you time to fix the issue without losing any events. **Retry Schedule:** | Attempt | Time After Previous | Total Time Elapsed | | - | - | - | | 1 | Immediate | 0 min | | 2 | 5 seconds | \~5 sec | | 3 | 5 minutes | \~5 min | | 4 | 30 minutes | \~35 min | | 5 | 2 hours | \~2h 35m | | 6 | 5 hours | \~7h 35m | | 7 | 10 hours | \~17h 35m | | 8 | 10 hours | \~27h 35m | Automatic retry stops after any of these conditions are met: * A 2xx response is received. * All 8 attempts have been completed. * The endpoint is disabled. If all attempts fail for 5 consecutive days, the endpoint is automatically disabled. ## Disabled endpoints If your webhook endpoint does not respond with a 2xx status code consistently, it's automatically disabled after 5 consecutive days of failures. The timer starts after the first failure, and a single successful delivery resets the timer. You receive an email notification when the webhook is disabled. You can re-enable a disabled webhook in the dashboard by editing the webhook. # Trusted IP allowlist for webhooks Source: https://docs.straddle.com/webhooks/security/ip-list Use Straddle's published IP allowlist to restrict inbound webhook traffic to your endpoints, ensuring secure communication for ACH event notifications. In case your webhook receiving endpoint is behind a firewall or NAT, you may need to allow traffic from Straddle's IP addresses. This is the full list of IP addresses that webhooks may originate from grouped by the region of the sender. ## Straddle IP addresses ### US ``` 44.228.126.217 50.112.21.217 52.24.126.164 54.148.139.208 2600:1f24:64:8000::/56 ``` The list is also available as a JSON file: [webhooks-ips.json](https://docs.svix.com/webhook-ips.json). # Manual webhook signature verification Source: https://docs.straddle.com/webhooks/security/manual Manually verify Straddle webhook signatures without an SDK, including the HMAC computation, header parsing, and timestamp checks for replay protection. Using the official libraries is the recommended and most straightforward method to verify webhooks (as discussed in the previous verification guide). However, there may be situations where you need to verify them manually. This section explains the manual verification process in detail. The recommended way to verify webhooks is using the official libraries. Consider that implementation strategy first. ## Verifying signatures manually Each webhook call includes three headers that are crucial for verifying authenticity: * **webhook-id**: A unique message identifier for the webhook message. This value is unique across all messages. If a webhook is resent (due to a previous failure), the `webhook-id` remains the same. * **webhook-timestamp**: The timestamp of the attempt in seconds since the Unix epoch. * **webhook-signature**: A Base64-encoded list of signatures (space-delimited). You use these headers, along with the raw request body, to generate and compare the expected signature. ## Constructing the signed content The content to sign is created by concatenating the `id`, `timestamp`, and `payload` (raw body of the request) with a `.` character between them: ```javascript signed-content.js theme={null} const signedContent = `${webhook_id}.${webhook_timestamp}.${body}`; ``` It's critical that you use the raw request body here. Any modifications (such as re-stringifying a parsed JSON body) will change the content and result in a signature mismatch. ## Determining the expected signature Straddle uses an HMAC with SHA-256 to sign its webhooks. To calculate the expected signature: 1. Extract the portion of your signing secret after the `whsec_` prefix. 2. Base64-decode that portion to get your key bytes. 3. Compute the HMAC using the decoded key and the `signedContent`. 4. Compare the result against the provided `webhook-signature` values. ### Example in Node.js ```javascript node-verify.js theme={null} const crypto = require('crypto'); const svix_id = "msg_p5jXN8AQM9LWM0D4loKWxJek"; const svix_timestamp = "1614265330"; const body = '{"test": 2432232314}'; const secret = "whsec_5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH"; const signedContent = `${svix_id}.${svix_timestamp}.${body}`; const secretBytes = Buffer.from(secret.split('_')[1], "base64"); const signature = crypto .createHmac('sha256', secretBytes) .update(signedContent) .digest('base64'); console.log(signature); // This signature should match one of those found in the `webhook-signature` header. ``` ## Comparing signatures The `webhook-signature` header often looks like this: ```bash theme={null} v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE= v1,bm9ldHUjKzFob2VudXRob2VodWUzMjRvdWVvdW9ldQo= v2,MzJsNDk4MzI0K2VvdSMjMTEjQEBAQDEyMzMzMzEyMwo= ``` Each signature is prefixed by a version identifier and a comma, such as `v1,`. To verify, remove the prefix (e.g., `v1,`) and compare the remaining Base64 string to your computed signature. Use a constant-time comparison method to compare signatures and prevent timing attacks. ## Verifying the timestamp The `webhook-timestamp` header includes the timestamp of the attempt. Make sure this timestamp is close to your current time (within a certain allowed skew, like a few minutes) to prevent replay attacks. ## Example signatures Here is an example you can use to validate your manual verification logic. Note that this may fail verification due to an old timestamp, and that’s expected if you’re strictly enforcing freshness. ```javascript manual-example.js theme={null} const secret = 'whsec_plJ3nmyCDGBKInavdOK15jsl'; const payload = '{"event_type":"ping","data":{"success":true}}'; const msg_id = 'msg_loFOjxBNrRLzqYUe'; const timestamp = '1731705121'; // The expected signature would be generated following the steps described above. // Replace with actual code to verify and compare the result. ``` You can also use the open-source [Standard Webhooks](https://www.standardwebhooks.com/simulate) simulation tool to generate as many examples as needed. # Verify webhook signatures with SDKs Source: https://docs.straddle.com/webhooks/security/sdks Securely verify Straddle webhook signatures and payloads using Svix SDKs in Node.js, Python, Ruby, Go, and other languages with code examples. # Verification SDKs When working with webhooks, it's crucial to ensure that the payloads you're receiving are genuinely from Straddle and haven't been tampered with. Payload verification helps you verify the authenticity of incoming requests by using security headers and signature checks, making your integration more secure against malicious actors. In this section, you'll learn how to verify Straddle payloads step-by-step. By following this guide, you can confidently establish that your server is interacting with trusted data, allowing you to safely process events without worrying about spoofed or modified payloads. Whether you're new to webhooks or just need a refresher, the following instructions provide everything you need to get started with secure webhook verification using Straddle. Straddle has teamed up with Svix to make webhook verification as secure and straightforward as possible. This partnership means you get the best in payload authenticity and security. ## Verify with Svix libraries To integrate with Straddle webhooks securely, you’ll need to install the Svix libraries for your language or framework of choice. Below are installation snippets for various languages and environments. ```bash javascript theme={null} npm install svix # Or yarn add svix ``` ```bash python theme={null} pip install svix ``` ```toml rust theme={null} # In Cargo.toml [dependencies] http = "1.0.0" svix = "1.20.0" ``` ```groovy kotlin theme={null} // Gradle: Add this dependency to your project's build file: implementation "com.svix.kotlin:svix-kotlin:0.x.y" //Maven: Add this dependency to your project's POM: com.svix.kotlin svix-kotlin 0.x.y ``` ```bash ruby theme={null} gem install svix ``` ```bash csharp theme={null} dotnet add package Svix ``` ```bash php theme={null} composer require svix/svix ``` ```groovy java theme={null} // Gradle: Add this dependency to your project's build file: implementation "com.svix:svix:0.x.y" // Maven: Add this dependency to your project's POM: com.svix svix 0.x.y ``` ```bash cli theme={null} # On macOS install via Homebrew: brew install svix/svix/svix # On Windows install via Scoop: scoop bucket add svix https://github.com/svix/scoop-svix.git scoop install svix # For other platforms, such as linux, checkout the CLI docs on Github. ``` ## Use the raw request body You need to use the raw request body when verifying webhooks, as the cryptographic signature is sensitive to even the slightest changes. Avoid parsing the request and then re-stringifying it before verification. The signature for each endpoint is available where you added the endpoint, e.g., the Straddle dashboard. ## Verifying payloads Below is example verification code for various languages using Svix SDKs. Each code snippet shows how to verify the raw request body using the provided headers and secret. ```javascript javascript theme={null} import { Webhook } from "svix"; const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; // These were all sent from the server const headers = { "svix-id": "msg_p5jXN8AQM9LWM0D4loKWxJek", "svix-timestamp": "1614265330", "svix-signature": "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=", }; const payload = '{"test": 2432232314}'; const wh = new Webhook(secret); // Throws on error, returns the verified content on success const verifiedPayload = wh.verify(payload, headers); ``` ```python python theme={null} from svix.webhooks import Webhook secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" headers = { "webhook-id": "msg_p5jXN8AQM9LWM0D4loKWxJek", "webhook-timestamp": "1614265330", "webhook-signature": "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=", } payload = '{"test": 2432232314}' wh = Webhook(secret) payload = wh.verify(payload, headers) ``` ```rust rust theme={null} use svix::webhooks::Webhook; let secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw".to_string(); let mut headers = http::HeaderMap::new(); headers.insert("webhook-id", "msg_p5jXN8AQM9LWM0D4loKWxJek"); headers.insert("webhook-timestamp", "1614265330"); headers.insert("webhook-signature", "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE="); let payload = b"{\"test\": 2432232314}"; let wh = Webhook::new(&secret).unwrap(); wh.verify(&payload[..], &headers).unwrap(); // returns Ok on success, Err otherwise ``` ```go go theme={null} import ( "net/http" svix "github.com/svix/svix-webhooks/go" ) func verify() error { secret := "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" headers := http.Header{} headers.Set("webhook-id", "msg_p5jXN8AQM9LWM0D4loKWxJek") headers.Set("webhook-timestamp", "1614265330") headers.Set("webhook-signature", "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=") payload := []byte(`{"test": 2432232314}`) wh, err := svix.NewWebhook(secret) if err != nil { return err } return wh.Verify(payload, headers) } ``` ```kotlin kotlin theme={null} import com.svix.kotlin.Webhook import java.net.http.HttpHeaders val secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" val headersMap = mapOf( "webhook-id" to listOf("msg_p5jXN8AQM9LWM0D4loKWxJek"), "webhook-timestamp" to listOf("1614265330"), "webhook-signature" to listOf("v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=") ) val headers = HttpHeaders.of(headersMap) { _, _ -> true } val payload = "{\"test\": 2432232314}" val webhook = Webhook(secret) webhook.verify(payload, headers) // throws WebhookVerificationError exception on failure. ``` ```ruby ruby theme={null} require 'svix' headers = { "webhook-id" => "msg_p5jXN8AQM9LWM0D4loKWxJek", "webhook-timestamp" => "1614265330", "webhook-signature" => "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=" } payload = '{"test": 2432232314}' wh = Svix::Webhook.new("whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw") json = wh.verify(payload, headers) ``` ```csharp csharp theme={null} using Svix; using System.Net; var secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; var headers = new WebHeaderCollection(); headers.Set("webhook-id", "msg_p5jXN8AQM9LWM0D4loKWxJek"); headers.Set("webhook-timestamp", "1614265330"); headers.Set("webhook-signature", "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE="); var payload = "{\"test\": 2432232314}"; var wh = new Webhook(secret); wh.Verify(payload, headers); // Throws on error ``` ```php php theme={null} 'msg_p5jXN8AQM9LWM0D4loKWxJek', 'webhook-timestamp' => '1614265330', 'webhook-signature' => 'v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=' ); $wh = new \Svix\Webhook('whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw'); $json = $wh->verify($payload, $header); // Throws on error, returns verified content on success ``` ```java java theme={null} import com.svix.Webhook; import java.net.http.HttpHeaders; import java.util.*; String secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; HashMap> headerMap = new HashMap<>(); headerMap.put("webhook-id", Arrays.asList("msg_p5jXN8AQM9LWM0D4loKWxJek")); headerMap.put("webhook-timestamp", Arrays.asList("1614265330")); headerMap.put("webhook-signature", Arrays.asList("v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=")); HttpHeaders headers = HttpHeaders.of(headerMap, (k,v)->true); String payload = "{\"test\": 2432232314}"; Webhook webhook = new Webhook(secret); webhook.verify(payload, headers); // throws WebhookVerificationError exception on failure. ``` ```bash cli theme={null} export SVIX_AUTH_TOKEN="AUTH_TOKEN" svix verify --secret whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw \ --msg-id msg_p5jXN8AQM9LWM0D4loKWxJek \ --timestamp 1614265330 \ --signature v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE= '{"test": 2432232314}' ``` ## Framework-specific examples Below are examples for how to handle raw request bodies and verification in various frameworks: ### Python (Django) ```python theme={null} from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse from svix.webhooks import Webhook, WebhookVerificationError secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" @csrf_exempt def webhook_handler(request): headers = request.headers payload = request.body try: wh = Webhook(secret) msg = wh.verify(payload, headers) except WebhookVerificationError: return HttpResponse(status=400) # Do something with the message... return HttpResponse(status=204) ``` ### Python (Flask) ```python theme={null} from flask import request, Flask from svix.webhooks import Webhook, WebhookVerificationError app = Flask(__name__) secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" @app.route('/webhook/', methods=['POST']) def webhook_handler(): headers = request.headers payload = request.get_data() try: wh = Webhook(secret) msg = wh.verify(payload, headers) except WebhookVerificationError: return ('', 400) # Do something with the message... return ('', 204) ``` ### Python (FastAPI) ```python theme={null} from fastapi import FastAPI, Request, Response, status from svix.webhooks import Webhook, WebhookVerificationError app = FastAPI() secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" @app.post("/webhook/", status_code=status.HTTP_204_NO_CONTENT) async def webhook_handler(request: Request, response: Response): headers = request.headers payload = await request.body() try: wh = Webhook(secret) msg = wh.verify(payload, headers) except WebhookVerificationError: response.status_code = status.HTTP_400_BAD_REQUEST return # Do something with the message... ``` ### Node.js (Next.js) ```javascript theme={null} import { Webhook } from "svix"; import { buffer } from "micro"; export const config = { api: { bodyParser: false, }, }; const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; export default async function handler(req, res) { const payload = (await buffer(req)).toString(); const headers = req.headers; const wh = new Webhook(secret); let msg; try { msg = wh.verify(payload, headers); } catch (err) { return res.status(400).json({}); } // Do something with the message... res.json({}); } ``` ### Node.js (Next.js 13 App Router) ```typescript theme={null} import { Webhook } from "svix"; const webhookSecret: string = process.env.WEBHOOK_SECRET || "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; export async function POST(req: Request) { const webhook_id = req.headers.get("webhook-id") ?? ""; const webhook_timestamp = req.headers.get("webhook-timestamp") ?? ""; const webhook_signature = req.headers.get("webhook-signature") ?? ""; const body = await req.text(); const svx = new Webhook(webhookSecret); let msg; try { msg = svx.verify(body, { "webhook-id": webhook_id, "webhook-timestamp": webhook_timestamp, "webhook-signature": webhook_signature, }); } catch (err) { return new Response("Bad Request", { status: 400 }); } console.log(msg); // Rest return new Response("OK", { status: 200 }); } ``` ### Node.js (Netlify Functions) ```typescript theme={null} import { Webhook } from "svix"; const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; export const handler = async ({body, headers}) => { const payload = body; const wh = new Webhook(secret); let msg; try { msg = wh.verify(payload, headers); } catch (err) { return { statusCode: 400, body: JSON.stringify({}) }; } // Do something with the message... return { statusCode: 200, body: JSON.stringify({}) }; }; ``` ### Node.js (Express) ```typescript theme={null} import { Webhook } from "svix"; import bodyParser from "body-parser"; import express from "express"; const app = express(); const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; app.post('/webhook', bodyParser.raw({ type: 'application/json' }), (req, res) => { const payload = req.body; const headers = req.headers; const wh = new Webhook(secret); try { wh.verify(payload, headers); } catch (err) { return res.status(400).json({}); } // Do something with the message... res.json({}); }); app.listen(3000, () => console.log('Server started on port 3000')); ``` ### Node.js (NestJS) **main.ts:** ```typescript theme={null} import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule, { rawBody: true }); await app.listen(3000); } bootstrap(); ``` **webhook.controller.ts:** ```typescript theme={null} import { Controller, Post, RawBodyRequest, Req } from '@nestjs/common'; import { Request } from 'express'; import { Webhook } from 'svix'; @Controller('webhook') class WebhookController { @Post() webhook(@Req() request: RawBodyRequest) { const secret = 'whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw'; const wh = new Webhook(secret); const payload = request.rawBody.toString('utf8'); const headers = request.headers; try { wh.verify(payload, headers); // Do something with the message... } catch (err) { // handle error } } } ``` ### Go (standard lib) ```go theme={null} package main import ( "io" "log" "net/http" svix "github.com/svix/svix-webhooks/go" ) const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" func main() { wh, err := svix.NewWebhook(secret) if err != nil { log.Fatal(err) } http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) { headers := r.Header payload, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) return } err = wh.Verify(payload, headers) if err != nil { w.WriteHeader(http.StatusBadRequest) return } // Do something with the message... w.WriteHeader(http.StatusNoContent) }) http.ListenAndServe(":8080", nil) } ``` ### Go (Gin) ```go theme={null} package main import ( "io" "log" "net/http" "github.com/gin-gonic/gin" svix "github.com/svix/svix-webhooks/go" ) const secret = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" func main() { wh, err := svix.NewWebhook(secret) if err != nil { log.Fatal(err) } r := gin.Default() r.POST("/webhook", func(c *gin.Context) { headers := c.Request.Header payload, err := io.ReadAll(c.Request.Body) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } err = wh.Verify(payload, headers) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Do something with the message... c.JSON(200, gin.H{}) }) r.Run() } ``` ### Rust (axum) ```rust theme={null} use axum::{body::Bytes, http::StatusCode}; use hyper::HeaderMap; use svix::webhooks::Webhook; pub const SECRET: &'static str = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"; pub async fn webhook_in(headers: HeaderMap, body: Bytes) -> StatusCode { let wh = Webhook::new(SECRET); if wh.is_err() { return StatusCode::INTERNAL_SERVER_ERROR; } if wh.unwrap().verify(&body[..], &headers).is_err() { return StatusCode::BAD_REQUEST; } // Do something with the message... StatusCode::NO_CONTENT } ``` ### Ruby (Ruby on Rails) **config/routes.rb:** ```ruby theme={null} Rails.application.routes.draw do post "/webhook", to: "webhook#index" end ``` **app/controllers/webhook\_controller.rb:** ```ruby theme={null} require 'svix' class WebhookController < ApplicationController protect_from_forgery with: :null_session def index begin payload = request.body.read headers = request.headers wh = Svix::Webhook.new("whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw") json = wh.verify(payload, headers) # Do something with the message... head :no_content rescue head :bad_request end end end ``` ### PHP (Laravel) ```php theme={null} use Illuminate\Http\Request; use Svix\Webhook; use Svix\Exception\WebhookVerificationException; Route::post('webhook', function(Request $request) { $payload = $request->getContent(); $headers = collect($request->headers->all())->map(fn($item) => $item[0]); try { $wh = new Webhook("whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"); $json = $wh->verify($payload, $headers->toArray()); // Do something with the message... return response()->noContent(); } catch (WebhookVerificationException $e) { return response(null, 400); } }); ``` # Why you should verify webhooks Source: https://docs.straddle.com/webhooks/security/why-verify Understand why verifying Straddle webhook signatures is critical for security, preventing spoofed events, and protecting your platform from fraudulent payloads. # Why Verify Webhooks Because of the way webhooks work, attackers can impersonate services by simply sending a fake webhook request to an endpoint. Think about it: it's just an HTTP POST from an unknown source. This scenario creates a potential security hole for many applications, or at the very least, a source of confusion and erroneous data processing. To prevent unauthorized requests, Straddle signs every webhook and its metadata with a unique key for each endpoint. By verifying this signature, you ensure that the webhook indeed comes from Straddle, processing it only if the verification passes. ## Preventing replay attacks Another potential vulnerability is a replay attack. In a [replay attack](https://en.wikipedia.org/wiki/Replay_attack), an attacker intercepts a valid payload (including the signature) and re-sends it to your endpoint. Because the payload is valid and signed, it would pass the normal verification checks, potentially causing unintended actions or security breaches. To combat this, Straddle includes a timestamp in every webhook attempt. The official libraries automatically reject webhooks if their timestamp is more than five minutes off from the current time. This requirement ensures that even if a payload is intercepted, it cannot be successfully replayed at a later time without failing the time-based validation check. For timestamp verification to be effective, it's important that your server's clock is accurate. Straddle recommends using [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) (Network Time Protocol) to keep your server's clock synchronized.