Partner API Reference
Quick-reference for all partner-accessible endpoints. For flow diagrams, webhook verification examples, and PCI scope notes see PARTNER_GUIDE.md.
Base URL and Authentication
Base URL: https://api.foundrypay.io
Auth: Authorization: ApiKey <your-api-key>
Content: Content-Type: application/json
Every request is automatically scoped to your merchant account. API keys are generated in the portal under Settings → API Keys.
Payment Requests
Create a Payment Request
POST /v1/payment-requests
Request body
| Field | Type | Required | Description |
|---|---|---|---|
referenceId |
string | Yes | Your order/invoice number. Returned in all webhooks. |
buyerEmail |
string | Yes | Buyer email. Enables saved-card recall for returning buyers. |
amount |
number | Yes | Amount in dollars (e.g. 312.50). Range: 0.01 – 1,000,000. |
currency |
string | No | ISO 4217. Default: "USD". |
captureMode |
string | No | "manual" (default) or "immediate". |
acceptedPaymentMethod |
string | No | "card", "ach", or omit to let buyer choose. |
buyerCompany |
string | No | Company name shown in the portal. |
returnUrl |
string | No | Redirect after payment on mobile. |
billingAddress |
object | No | See Billing Address. |
lineItems |
array | No | See Line Items. Amounts in cents. |
Response 201
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"token": "abc123xyz...",
"iframeUrl": "https://pay.foundrypay.io/enter/abc123xyz...",
"status": "Pending",
"expiresAt": "2024-06-01T13:00:00Z"
}
Expires after 60 minutes.
Get Payment Request Status
GET /v1/payment-requests/{token}
Pass the string token (not the UUID) returned from the create call.
Response 200
{
"id": "3fa85f64-...",
"referenceId": "ORD-20240601-001",
"buyerEmail": "buyer@example.com",
"buyerCompany": "Acme Wholesale",
"amount": 312.50,
"currency": "USD",
"status": "Collected",
"createdAt": "2024-06-01T12:00:00Z",
"expiresAt": "2024-06-01T13:00:00Z",
"completedAt": "2024-06-01T12:34:56Z",
"acceptedPaymentMethod": "card"
}
| Status | Meaning |
|---|---|
Pending |
Waiting for buyer to complete payment. |
Collected |
Card entered. Ready to authorize. |
Expired |
60-minute window elapsed. |
Cancelled |
Cancelled by the platform. |
Request Card Refresh
When a stored card has expired or been declined during authorization, send the buyer a link to enter a replacement card.
POST /v1/payment-requests/{id}/card-update
The {id} is the UUID of the source payment request (status must be Collected).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
returnUrl |
string | No | Mobile redirect after card entry. |
Response 201
{
"id": "9b1b3a2e-...",
"token": "xyz789...",
"iframeUrl": "https://pay.foundrypay.io/enter/xyz789...",
"expiresAt": "2024-06-01T14:00:00Z"
}
Show or send the iframeUrl to the buyer. On completion:
- The source payment request's stored card is replaced with the new one.
- A
card.updatedwebhook is delivered to your endpoint. - Re-call
POST /v1/paymentswith the samepaymentRequestId— the new card is used automatically.
Expires after 60 minutes.
Card Enrollment
Store a card on file without tying it to any specific order or invoice.
POST /v1/card-enrollments
Request body
| Field | Type | Required | Description |
|---|---|---|---|
buyerEmail |
string | Yes | Buyer email. Used as the Adyen shopper identifier. |
buyerReference |
string | No | Your own buyer/account ID. Returned in the card.enrolled webhook. |
buyerCompany |
string | No | Company name (display only). |
returnUrl |
string | No | Mobile redirect after card entry. |
billingAddress |
object | No | Pre-populated in the form. See Billing Address. |
Response 201
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"token": "abc123xyz...",
"iframeUrl": "https://pay.foundrypay.io/enter/abc123xyz...",
"expiresAt": "2024-06-01T13:00:00Z"
}
Show the iframeUrl to the buyer. On completion you receive a card.enrolled webhook with the
paymentMethodId. Use that ID in future POST /v1/payments calls.
Expires after 60 minutes.
Payments
Authorize
Authorize and capture the funds for a Collected payment request.
POST /v1/payments
Request body
| Field | Type | Required | Description |
|---|---|---|---|
paymentRequestId |
UUID | Yes | ID of the Collected payment request. |
Response 200
{
"id": "7c4a9e1d-...",
"status": "Authorized",
"pspReference": "853612...",
"amount": 312.50,
"currency": "USD",
"referenceId": "ORD-20240601-001",
"authorizedAt": "2024-06-01T12:35:00Z"
}
| Payment Status | Meaning |
|---|---|
Authorized |
Funds held. Capture via portal to settle. |
Captured |
Funds settled (immediate-capture mode or manual capture). |
Failed |
Authorization declined. |
Voided |
Authorization cancelled before capture. |
Refunded |
Post-capture refund issued. |
Batch Authorize
Authorize multiple payment requests in one call. Always returns HTTP 200; inspect each item's
success field — the batch status code does not indicate per-item success.
POST /v1/payments/batch-authorize
Request body
{
"items": [
{ "referenceId": "ORD-001" },
{ "referenceId": "ORD-002", "amount": 150.00 }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
items[].referenceId |
string | Yes | Your order/invoice reference. |
items[].amount |
number | No | Override the payment request amount (advanced use). |
Response 200
{
"results": [
{ "referenceId": "ORD-001", "success": true, "paymentId": "7c4a9e1d-..." },
{ "referenceId": "ORD-002", "success": false, "error": "No collected payment request found" }
],
"summary": { "total": 2, "succeeded": 1, "failed": 1 }
}
Transactions
List Transactions
GET /v1/transactions
Query parameters
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by payment status (e.g. Authorized, Captured). |
search |
string | Full-text search on reference ID or buyer email. |
paymentRequestId |
UUID | Return only transactions for a specific payment request. |
from |
ISO 8601 | Earliest transaction date. |
to |
ISO 8601 | Latest transaction date. |
page |
integer | Page number (1-based). |
pageSize |
integer | Results per page (default 20). |
Response 200 — paginated list of payment objects.
Shared Object Schemas
Billing Address
{
"street": "123 Main St",
"houseNumberOrName": "Suite 400",
"city": "Chicago",
"stateOrProvince": "IL",
"postalCode": "60601",
"country": "US"
}
All fields optional; any provided are forwarded to the card network for AVS.
Line Items
Array of objects for Level 3 interchange qualification. Amounts in cents.
[
{
"id": "SKU-001",
"description": "Widget A",
"quantity": 2,
"amountExcludingTax": 25000,
"amountIncludingTax": 25000,
"taxAmount": 0,
"taxPercentage": 0
}
]
Webhooks
Envelope
All webhooks share a common envelope:
{
"eventType": "payment_request.completed",
"createdAt": "2024-06-01T12:34:56Z",
"data": { }
}
Event Payloads
payment_request.completed
{
"referenceId": "ORD-20240601-001",
"status": "collected",
"paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
card.enrolled
{
"buyerReference": "BUYER-4521",
"buyerEmail": "buyer@example.com",
"paymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"last4": "1111",
"brand": "visa"
}
card.updated
{
"referenceId": "ORD-20240601-001",
"paymentMethodId": "7c4a9e1d-...",
"last4": "4242",
"brand": "mastercard"
}
payment_request.expired
{
"referenceId": "ORD-20240601-001"
}
Signature Verification
Every webhook includes X-Foundry-Signature: sha256=<hex-digest>.
import hmac, hashlib
def verify(secret: str, body: bytes, header: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, header)
bool Verify(string secret, byte[] body, string header)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var digest = "sha256=" + Convert.ToHexString(hmac.ComputeHash(body)).ToLower();
return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(digest),
Encoding.UTF8.GetBytes(header));
}
Respond with any 2xx to acknowledge. Failed deliveries are retried 3 times with exponential
backoff.
Error Responses
{ "error": "Payment request not found or not in collected state" }
| HTTP Status | Meaning |
|---|---|
400 |
Missing required field or invalid value. |
401 |
Invalid or missing API key. |
404 |
Resource not found. |
409 |
Conflict — e.g. payment request already collected or expired. |
422 |
Payment could not be processed (e.g. declined). |
502 |
Upstream error from payment network. Retry after a short delay. |
Test Cards
| Scenario | Card Number | Expiry | CVV |
|---|---|---|---|
| Visa — success | 4111 1111 1111 1111 |
Any future | Any 3 digits |
| Mastercard — success | 5500 0000 0000 0004 |
Any future | Any 3 digits |
| Declined | 4000 0000 0000 0002 |
Any future | Any 3 digits |
| Insufficient funds | 4000 0000 0000 9995 |
Any future | Any 3 digits |
ACH testing: routing 021000021, any 10-digit account number.