{"openapi":"3.0.4","info":{"title":"Payra Onboarding API","version":"1.0.0","description":"**Authentication (two patterns on the same bridge):**\n\n1. **`Authorization: Basic`** — username = API **key id**, password = **secret**. A **tenant integration** key (no merchant scope) may **`POST /api/v1/applicants`** only; read routes return **403**.\n\n2. **Portal server** — `X-Admin-Secret` (must match the bridge `INTERNAL_ADMIN_SECRET`) plus `X-Tenant-Id` (existing tenant id). Used by the Payra portal to list applicants, fetch detail, signing links, and PDFs.\n\nA **merchant-scoped** Basic key is limited to its linked applicant for reads (and other merchant-scoped behavior documented per route)."},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}],"paths":{"/health":{"get":{"tags":["Health"],"summary":"Liveness","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"service":{"type":"string"}}}}}}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"/api/v1/applicants":{"get":{"tags":["Bridge — Applications & accounts"],"summary":"List applicants (paginated)","description":"Returns applicant rows for the authenticated tenant (`data`, `page`, `pageSize`, `total`).\n\n**Not available** with the **tenant integration** API key (403) — use the Payra portal or a **merchant-scoped** key.\n\n**Portal:** `X-Admin-Secret` + `X-Tenant-Id` (must match `INTERNAL_ADMIN_SECRET` and a real tenant on the bridge).\n\n**Merchant-scoped key:** returns at most the applicant linked to that merchant.\n\n**Query:** `page` (default 1), `pageSize` (default 20, max 100).","security":[{"basic":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Paginated applicants.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicantsPage"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Returned when authenticating with the tenant integration key (listing is reserved for portal / merchant-scoped credentials)."}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"post":{"tags":["Bridge — Applications & accounts"],"summary":"Submit application (primary ISV onboarding operation)","description":"**Primary operation for ISV integrations:** create an applicant in one `application/json` request.\n\n**Authentication:** `Authorization: Basic` with your **tenant integration** API key id and secret (the key without a merchant scope).\n\n**Body:** `status` (`draft` or `submitted`) and `payload` containing business data, primary contact, `individuals` (controllers/officers), and `documents`.\n\n**Documents:** each item in `payload.documents` includes metadata plus `dataBase64` (standard base64 file bytes). Tag each file with `scope`: `organization` (business), `individual` (identity docs; set `individualIndex` to match `payload.individuals[i]`), or `other`. You can send the complete application—including every controller and every file—in a **single POST**.\n\nThe hosted Payra portal form is a reference implementation of the same `payload` shape; you can build your own UI and POST the equivalent JSON.","security":[{"basic":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApplicantRequest"}}}},"responses":{"201":{"description":"Created. Response includes `id` (applicant id). When `status` is `submitted` and PandaDoc is configured, behavior depends on the tenant's async/sync onboarding setting (`pandadocAgreementSetupMode` on the response). Async (default): fast 201 with `agreementSetupStatus: pending` — poll `GET /api/v1/applicants/{applicantId}`. Sync: request blocks until setup completes; `nextAction` may be included. Repair endpoint always runs synchronously.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"applicant":{"type":"object"},"agreementSetupStatus":{"type":"string","enum":["pending","ready","failed","not_applicable"]},"pandadocAgreementSetupMode":{"type":"string","enum":["async","sync"],"description":"Effective mode for this submit (tenant portal setting; may be overridden by ops env)."},"nextAction":{"$ref":"#/components/schemas/EmbeddedSignatureNextAction"},"agreementSetupError":{"type":"string","description":"Present when PandaDoc signing could not be started (repair endpoint or legacy sync path)."}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"/api/v1/applicants/{applicantId}":{"get":{"tags":["Bridge — Applications & accounts"],"summary":"Get applicant by id","description":"Returns a single applicant row (same shape as items in `GET /api/v1/applicants`).\n\n**Not available** with the **tenant integration** API key (403).\n\n**Merchant-scoped key:** only the applicant id linked to the merchant is accessible (404 otherwise).","security":[{"basic":[]}],"parameters":[{"name":"applicantId","in":"path","required":true,"schema":{"type":"string"},"description":"Applicant id (`id` from `POST /api/v1/applicants` or list response)."}],"responses":{"200":{"description":"Applicant row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Applicant"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Tenant integration key cannot call this route."},"404":{"description":"Applicant not found or not visible for this credential."}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"/api/v1/applicants/{applicantId}/pandadoc-signing-link":{"get":{"tags":["Bridge — Applications & accounts"],"summary":"Resolve PandaDoc hosted signing URL","description":"Fetches the PandaDoc recipient signing link for the merchant agreement when the document and recipient `shared_link` exist.\n\n**Not available** with the **tenant integration** API key (403). Requires portal or merchant-scoped auth with access to the applicant.","security":[{"basic":[]}],"parameters":[{"name":"applicantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Signing link payload (URLs may be null if not yet available).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PandaDocSigningLinkResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Tenant integration key cannot call this route."},"404":{"description":"Applicant or agreement not found, or hosted signing link not yet available from PandaDoc."},"502":{"description":"PandaDoc request failed (unexpected)."},"503":{"description":"PandaDoc agreement environment not configured on this bridge."}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"/api/v1/applicants/{applicantId}/merchant-agreement-signed-pdf":{"get":{"tags":["Bridge — Applications & accounts"],"summary":"Download stored signed merchant agreement PDF","description":"Returns `application/pdf` bytes when Payra has stored the completed agreement PDF for this applicant.\n\n**Not available** with the **tenant integration** API key (403). Requires portal or merchant-scoped auth with access to the applicant.","security":[{"basic":[]}],"parameters":[{"name":"applicantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PDF file (`Content-Disposition: attachment`).","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Tenant integration key cannot call this route."},"404":{"description":"Applicant not found or signed PDF not stored yet."}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"/api/v1/applicants/{applicantId}/pandadoc/agreement":{"post":{"tags":["Bridge — Applications & accounts"],"summary":"Create or reuse PandaDoc merchant agreement document","description":"Creates a PandaDoc document from the merchant agreement template using the applicant `payload`, polls until `document.draft`, prefills tokens/fields, and persists `draft_ready`. Returns the existing agreement when one is already stored (unless `force=true`).\n\n**Order:** call after `POST /api/v1/applicants` (application must exist first). Then call `POST .../pandadoc/signing-session` to silent-send and start embedded signing.\n\nSubmitting with `status: submitted` on `POST /api/v1/applicants` runs this step and signing-session automatically when PandaDoc env is configured (`nextAction` on the response).\n\n**Auth:** tenant integration key, portal admin secret + tenant header, or merchant-scoped key for that applicant.","security":[{"basic":[]}],"parameters":[{"name":"applicantId","in":"path","required":true,"schema":{"type":"string"},"description":"Applicant id returned from `POST /api/v1/applicants`."},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"When `true`, deletes the stored agreement row and creates a new PandaDoc document."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Same as query `force`; body wins when both are present."}}}}}},"responses":{"200":{"description":"Agreement document created or reused.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PandaDocAgreementDocumentResponse"}},"required":["data"]}}}},"400":{"description":"Applicant payload cannot be mapped to PandaDoc fields/tokens."},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden for this credential or applicant."},"404":{"description":"Applicant not found"},"502":{"description":"PandaDoc request failed"},"503":{"description":"PandaDoc agreement environment not configured on this bridge."}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"/api/v1/applicants/{applicantId}/pandadoc/signing-session":{"post":{"tags":["Bridge — Applications & accounts"],"summary":"Create PandaDoc embedded signing session (and hosted link)","description":"After `POST .../pandadoc/agreement` (document `draft_ready`), silent-sends if needed and creates an embedded signing session. Response `data` matches `nextAction` on applicant submit: `sessionId` for the PandaDoc embed SDK, optional `pandadocSigningUrl` (recipient `shared_link`) to share signing outside your app.","security":[{"basic":[]}],"parameters":[{"name":"applicantId","in":"path","required":true,"schema":{"type":"string"},"description":"Applicant id returned from `POST /api/v1/applicants`."}],"responses":{"200":{"description":"Signing session created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EmbeddedSignatureNextAction"}},"required":["data"]}}}},"401":{"description":"Unauthorized"},"404":{"description":"No agreement or applicant not found"},"409":{"description":"Document not ready for signing"}},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]},"servers":[{"url":"https://staging-paymentsapi.payra.com","description":"Payra onboarding API (hosted by Payra). Shows only `/api/v1/...` onboarding/application endpoints."}]}},"components":{"schemas":{"ApplicantDocument":{"type":"object","description":"One uploaded file embedded in the application. Prefer a **single** `POST` with all documents in `payload.documents` (base64). Set `scope` and `individualIndex` so reviewers can group files by organization vs each controller.","required":["label","fileName","contentType","sizeBytes","dataBase64"],"properties":{"label":{"type":"string","description":"Display name (e.g. \"Bank statement\", \"Passport\").","example":"Bank statement"},"fileName":{"type":"string","example":"statement.pdf"},"contentType":{"type":"string","example":"application/pdf"},"sizeBytes":{"type":"integer","example":240000},"dataBase64":{"type":"string","description":"Raw file bytes encoded as standard base64 (no data: URL prefix)."},"scope":{"type":"string","enum":["organization","individual","other"],"description":"`organization` — business docs; `individual` — identity docs for a person; `other` — voided check, etc."},"individualIndex":{"type":"integer","minimum":0,"description":"When `scope` is `individual`, index into `payload.individuals` (0 = first person)."}}},"ApplicantPayload":{"type":"object","description":"Full merchant onboarding snapshot. Send in one request with `status: submitted` (or `draft` while iterating). Matches the Payra portal demo form: business, address, contact, controllers/officers, financial (banking + estimates), embedded files.","properties":{"schemaVersion":{"type":"integer","example":1},"submittedAt":{"type":"string","format":"date-time"},"company":{"type":"object","properties":{"legalName":{"type":"string"},"dba":{"type":"string"},"ein":{"type":"string"},"entityType":{"type":"string"},"industry":{"type":"string"},"website":{"type":"string","format":"uri"},"stateOfFormation":{"type":"string","description":"State or province where the legal entity was formed (maps to PandaDoc `StateOfFormation` on the merchant agreement)."}}},"address":{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string","example":"US"}}},"contact":{"type":"object","description":"Primary onboarding contact (may overlap with a controller).","properties":{"name":{"type":"string"},"title":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"}}},"individuals":{"type":"array","description":"Controllers, officers, beneficial owners (e.g. up to 3 in the hosted form). Each may have multiple `roles` and optional `ownershipPercent` when Owner.","items":{"$ref":"#/components/schemas/ApplicantIndividual"}},"financial":{"$ref":"#/components/schemas/ApplicantFinancial"},"notes":{"type":"string"},"documents":{"type":"array","items":{"$ref":"#/components/schemas/ApplicantDocument"}}}},"ApplicantFinancial":{"type":"object","description":"Banking and monthly processing estimates (hosted portal: after controllers, before org documents).","properties":{"accountType":{"type":"string","enum":["corporate_checking","corporate_savings"]},"accountHolder":{"type":"string"},"bankName":{"type":"string","description":"Depository institution name (maps to PandaDoc `BankName`)."},"routingNumber":{"type":"string","description":"US ABA routing; 9 digits."},"accountNumber":{"type":"string"},"estimatedMonthlyAchVolumeUsd":{"type":"number","minimum":0},"estimatedMonthlyAchCount":{"type":"integer","minimum":0},"estimatedMonthlyCheckVolumeUsd":{"type":"number","minimum":0},"estimatedMonthlyCheckCount":{"type":"integer","minimum":0},"useSameAccountForSettlementAndFees":{"type":"boolean","description":"When true, the linked bank account is used for both ACH settlement and fees (PandaDoc `UseSameAccountForSettlementAndFees`). Omit for legacy payloads; integrations should send an explicit value."}}},"ApplicantIndividual":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"jobTitle":{"type":"string"},"phone":{"type":"string"},"homeAddress":{"type":"object","properties":{"line1":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"}}},"taxId":{"type":"string","description":"Personal tax identifier (e.g. US SSN or ITIN, typically 9 digits). Prefer field name `taxId`; `ssn` is treated as an alias in UIs."},"dateOfBirth":{"type":"string","format":"date"},"driversLicenseNumber":{"type":"string","description":"Government-issued ID number (agreement field `SignerDriverLicenseNumber`)."},"driversLicenseIssuingState":{"type":"string","description":"Issuing state or province (`SignerDriversLicenseIssuingState`)."},"driversLicenseIssueDate":{"type":"string","format":"date","description":"`SignerDriversLicenseIssueDate`."},"driversLicenseExpirationDate":{"type":"string","format":"date","description":"`SignerDriversLicenseExpirationDate`."},"countryOfCitizenship":{"type":"string","description":"Country name or code (`SignerCountryOfCitizenship`)."},"roles":{"type":"array","items":{"type":"string","enum":["director","signatory","owner"]},"description":"Person may have several roles."},"ownershipPercent":{"type":"number","description":"Relevant when `owner` is in `roles`."}}},"CreateApplicantRequest":{"type":"object","properties":{"status":{"type":"string","enum":["draft","submitted"],"description":"Use `submitted` when the payload is complete."},"payload":{"$ref":"#/components/schemas/ApplicantPayload"},"processorApplicationId":{"type":"string","nullable":true}}},"EmbeddedSignatureNextAction":{"type":"object","description":"Returned when Payra PandaDoc agreement signing is configured. The ISV opens embedded signing in a modal using `sessionId` (see PandaDoc embedded signing SDK). `pandadocSigningUrl` is PandaDoc’s hosted recipient link (`shared_link` from document details) for sharing outside the embed.","required":["type","provider","label","documentId","sessionId","region","expiresInSeconds"],"properties":{"type":{"type":"string","enum":["embedded_signature"]},"provider":{"type":"string","enum":["pandadoc"]},"label":{"type":"string","example":"Review & Sign Agreement"},"documentId":{"type":"string"},"sessionId":{"type":"string"},"region":{"type":"string","description":"`us` or `eu` — PandaDoc API region for the signing widget."},"expiresInSeconds":{"type":"integer","minimum":60},"pandadocSigningUrl":{"type":"string","format":"uri","description":"Optional. PandaDoc hosted signing page for the merchant signer (same document as embed). Present when document details include `recipients[].shared_link` for `payload.contact.email`. Use for SMS/email handoff; silent send avoids PandaDoc emailing this link automatically.","example":"https://app.pandadoc.com/document/b7f11ea3c09d1c11208cc122457d4f3a2829d364"}}},"Applicant":{"type":"object","description":"Applicant database row returned by list/detail routes. `payload` is the onboarding JSON snapshot (same shape as `CreateApplicantRequest.payload`).","properties":{"id":{"type":"string"},"tenantId":{"type":"string"},"status":{"type":"string","enum":["draft","submitted","in_review","needs_information","approved","rejected","converted"]},"payload":{"type":"object","nullable":true,"additionalProperties":true},"processorApplicationId":{"type":"string","nullable":true},"rejectionReason":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ApplicantsPage":{"type":"object","required":["data","page","pageSize","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Applicant"}},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0}}},"PandaDocSigningLinkResponse":{"type":"object","description":"Hosted PandaDoc signing URL for the agreement signer when available (from document `recipients[].shared_link`). `pandadocDocumentId` is the PandaDoc document id.","properties":{"pandadocSigningUrl":{"type":"string","format":"uri","nullable":true},"pandadocDocumentId":{"type":"string","nullable":true},"signerEmail":{"type":"string","format":"email","nullable":true}}},"PandaDocAgreementDocumentResponse":{"type":"object","description":"PandaDoc merchant agreement document for an applicant. Created from the configured template using the applicant `payload` for tokens and fields. Idempotent unless `force=true`.","required":["pandadocDocumentId","providerStatus","agreementStatus","onboardingAgreementId"],"properties":{"pandadocDocumentId":{"type":"string","description":"PandaDoc document id."},"providerStatus":{"type":"string","description":"Last PandaDoc document status (e.g. `document.draft`).","example":"document.draft"},"agreementStatus":{"type":"string","enum":["pending_creation","draft_ready","sent","completed","cancelled","declined","error"],"description":"Payra onboarding agreement row status after create or reuse."},"onboardingAgreementId":{"type":"string","description":"Payra `onboarding_agreement` row id."}}}},"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}}}