| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
Submit a Reserve Funding Request
POST /api/v1/reserve-funding/requests
Submits a signed reserve funding agreement to Netevia HQ for review. The agreement itself is negotiated outside HQ — the external service sets the terms and the merchant signs the document — so this call is where that already-signed request enters the system. HQ does not obtain consent; it validates the data, stores the signed document, and creates a Pending request in the Reserve Funding Requests review queue for a Netevia employee to Approve or Reject.
This is the first of two related endpoints. Use GET /api/v1/reserve-funding/requests/{externalRequestId} to read back the decision — it is the authoritative status, complementing the best-effort decision callback.
Authentication
Basic HTTP authentication. The API user must have the Reserve Funding API access permission (referred to internally as the "allow Reserve Funding Management API" role option) and the manage-reserve-funding-requests module enabled. Without either, the call fails with 403.
Request body
{
"externalRequestId": "RF-2026-09-0001",
"merchant": {
"mid": "9180465590107730",
"dbaName": "The Best Tires"
},
"fundingDepartment": {
"departmentId": "STG824-RSV-9180",
"departmentName": "Reserve API Approval"
},
"fundingTerms": {
"startDate": "2026-09-15",
"stopDate": "2026-12-31",
"percent": 11,
"ceiling": 25000
},
"document": {
"fileName": "Reserve-Agreement-The-Best-Tires.pdf",
"fileType": "pdf",
"fileUrl": "https://files.example.com/agreements/best-tires.pdf"
},
"email": "[email protected]"
}Fields
Validation is exhaustive — every failing rule is returned together in one response, so you never fix one error only to discover another on the next attempt.
| Field | Type | Required | Notes |
|---|---|---|---|
externalRequestId | string | Required | Your own identifier for the request. Echoed on every response and used as the path parameter when reading the decision back. Trimmed before storage/comparison; max 64 characters. This is the idempotency key — see below. Uniqueness is scoped to your API user, so another integrator can reuse the same string without colliding with you. |
merchant.mid | string | Required | The merchant's MID at Netevia, resolved at submit time. If approved, this is the merchant the reserve is created on. Max 32 characters. The lookup is exact and not trimmed — a stray leading/trailing space fails it with merchant not found. |
merchant.dbaName | string | Required | Trading name, stored on the request and shown to the reviewer. Max 128 characters. Not checked against the merchant record — whatever you send is what the reviewer sees, so a mismatch slows the review down rather than failing the call. |
fundingDepartment.departmentId | string | Required | Selects the reserve department — the account and routing number the withheld funds are held against. Netevia provisions these and supplies the id. Max 64 characters. Must match a live department (department not found otherwise) and must be a Reserve department, indicator 2 — a Risk department (indicator 1) is refused with Risk departments are not accepted. The department's bank must also match the merchant's bank, but that is not checked at submit time; a mismatch surfaces later as a failed processingResult after approval. |
fundingDepartment.departmentName | string | Required | Free text stored alongside the request and shown in the review queue. Max 128 characters. Not matched against the department record — departmentId is what actually selects the department. |
fundingTerms.startDate | date | Required | Date the reserve begins accruing. ISO date or date-time. |
fundingTerms.stopDate | date | Optional | Date the reserve stops. Omit entirely for an open-ended reserve. Must be on or after startDate, else fundingTerms.stopDate must be on or after fundingTerms.startDate. |
fundingTerms.percent | number | One of percent/amount required | Percentage of each settlement withheld, as a number, not a fraction — 10 means 10%. Greater than 0, at most 100. Rounded to 4 decimal places (away from zero) before validation, so a value under 0.00005 is rejected rather than silently stored as zero. |
fundingTerms.amount | number | One of percent/amount required | Fixed amount withheld per settlement, instead of or in addition to percent. Send both and both rules apply. Greater than 0, at most 9,999,999.99 (the widest value the fixed-width TSYS record can carry). Same 4-decimal rounding as percent. At least one of percent/amount is required, else At least one of fundingTerms.percent or fundingTerms.amount is required., reported against the fundingTerms field. |
fundingTerms.ceiling | number | Required | Total at which the reserve stops accruing, regardless of whether you used percent, amount, or both. Greater than 0, at most 9,999,999.99. Same 4-decimal rounding. |
document.fileUrl | string | Required | Where Netevia fetches the signed agreement from. The download happens synchronously inside this call — an unreachable URL fails the request rather than failing later in review. Must be reachable from Netevia's servers without a login; a URL that only resolves inside your own network will fail with Document could not be retrieved from the provided URL. |
document.fileName | string | Required | The name given to the stored file, and the link text the reviewer clicks. Independent of the URL — you can serve a1b2c3.pdf from fileUrl and have it stored under this name. Max 256 characters; must not contain " < > | : * ? / \. The extension, not fileType, decides the stored type and must be pdf, jpg, jpeg, or png — a .docx name is refused even when fileType says pdf. |
document.fileType | string | Required | Declared file type: one of pdf, jpg, png (jpeg accepted as an alias for jpg). Trimmed and case-insensitive. Anything else → document.fileType must be one of: pdf, jpg, png. |
document.fileAccessToken | string | Optional | Sent as Authorization: Bearer … with the download, when your file store requires one. Omit for a plain public URL. |
email | string | Required | Contact address stored on the request and displayed in the review queue. Max 256 characters. Not validated as an email format, and no mail is ever sent to it — it is a display field for the reviewer, not a notification channel. |
Responses
200 — Created
200 — Created{
"data": {
"requestId": "HQ-RF-REQ-101",
"externalRequestId": "RF-2026-09-0001",
"status": "Pending",
"duplicate": false
},
"requestId": 407166,
"success": true
}A successful submission answers 200, not 201 — this is the general Netevia HQ platform convention for creation calls. data.requestId is the internal HQ-RF-REQ-<n> reference, identical to the one the GET endpoint and the decision callback will use.
200 — Duplicate (idempotent replay, nothing created)
200 — Duplicate (idempotent replay, nothing created){
"data": {
"requestId": "HQ-RF-REQ-101",
"externalRequestId": "RF-2026-09-0001",
"status": "Approved",
"duplicate": true
},
"requestId": 407170,
"success": true
}Re-submitting an externalRequestId you've already used returns the original request with duplicate: true — and that request's current status, which may already be Approved or Rejected. This is a safe retry, not an error: it is the intended way to recover from a timeout or a network failure on your side, so treat duplicate: true as "already submitted, go read the status" rather than as a failure.
400 — Validation failed (nothing created)
400 — Validation failed (nothing created){
"requestId": 407184,
"success": false,
"validationErrors": [
{ "field": "document.fileType", "error": "document.fileType must be one of: pdf, jpg, png." },
{ "field": "merchant.mid", "error": "merchant not found" },
{ "field": "fundingTerms", "error": "At least one of fundingTerms.percent or fundingTerms.amount is required." }
]
}The message key is error, not message. field uses dotted paths matching the request body, except for cross-field rules (such as the percent/amount check above), which are reported against their parent object.
403 — Forbidden
403 — ForbiddenReturned when the authenticated API user is missing the manage-reserve-funding-requests module or the "allow Reserve Funding Management API" role option.
Notes
- Idempotency:
externalRequestIdis the dedup key, scoped per API user. Retrying a POST after a timeout is always safe. - Synchronous document fetch: the signed document is downloaded during this call, not asynchronously afterward — a slow or unreachable file URL will fail the submission itself.
- This call never returns a decision. It only ever creates a
Pendingrequest (or reports a duplicate of one already submitted). The decision comes later, via the GET endpoint or the callback.
OpenAPI definition
{
"openapi": "3.0.0",
"info": {
"version": "v1",
"title": "Netevia HQ | API Documentation",
"description": "Netevia HQ | API Documentation"
},
"paths": {
"/api/v1/reserve-funding/requests": {
"post": {
"tags": ["ReserveFundingApi"],
"summary": "Submit a Reserve Funding Request",
"operationId": "ReserveFundingApi_SubmitReserveFundingRequest",
"requestBody": {
"content": {
"application/json": { "schema": { "$ref": "#/components/schemas/ReserveFundingApiRequest" } },
"text/json": { "schema": { "$ref": "#/components/schemas/ReserveFundingApiRequest" } },
"application/xml": { "schema": { "$ref": "#/components/schemas/ReserveFundingApiRequest" } },
"text/xml": { "schema": { "$ref": "#/components/schemas/ReserveFundingApiRequest" } },
"application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/ReserveFundingApiRequest" } }
},
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": { "schema": { "type": "object" } },
"text/json": { "schema": { "type": "object" } },
"application/xml": { "schema": { "type": "object" } },
"text/xml": { "schema": { "type": "object" } }
}
}
}
}
}
},
"security": [{ "Basic": [] }],
"servers": [{ "url": "https://hq.staging.netevia.dev" }],
"components": {
"securitySchemes": {
"Basic": { "type": "http", "description": "Basic HTTP Authentication", "scheme": "basic" }
},
"schemas": {
"ReserveFundingApiRequest": {
"type": "object",
"properties": {
"externalRequestId": { "type": "string" },
"merchant": { "$ref": "#/components/schemas/ReserveFundingApiMerchant" },
"fundingDepartment": { "$ref": "#/components/schemas/ReserveFundingApiDepartment" },
"fundingTerms": { "$ref": "#/components/schemas/ReserveFundingApiTerms" },
"document": { "$ref": "#/components/schemas/ReserveFundingApiDocument" },
"email": { "type": "string" }
}
},
"ReserveFundingApiMerchant": {
"type": "object",
"properties": { "mid": { "type": "string" }, "dbaName": { "type": "string" } }
},
"ReserveFundingApiDepartment": {
"type": "object",
"properties": { "departmentId": { "type": "string" }, "departmentName": { "type": "string" } }
},
"ReserveFundingApiTerms": {
"type": "object",
"properties": {
"startDate": { "format": "date-time", "type": "string" },
"stopDate": { "format": "date-time", "type": "string" },
"percent": { "format": "double", "type": "number" },
"amount": { "format": "double", "type": "number" },
"ceiling": { "format": "double", "type": "number" }
}
},
"ReserveFundingApiDocument": {
"type": "object",
"properties": {
"fileName": { "type": "string" },
"fileType": { "type": "string" },
"fileUrl": { "type": "string" },
"fileAccessToken": { "type": "string" }
}
}
}
}
}