Overview

Outpost Hosted Onboarding lets you onboard your existing merchants to Outpost services with minimal merchant friction. You retain full control over the merchant relationship, entry point, and checkout experience. Outpost provides the onboarding infrastructure, review workflow, and operations underneath.

Integration Flow

Your SystemOutpost APIHosted UIOutpost Ops
  • You initiate - Call the Outpost API with the merchant's company data to create an onboarding application
  • Merchant completes - Redirect the merchant to the Outpost-hosted onboarding UI where they fill in product-specific details and submit
  • Outpost reviews - Outpost reviews the application asynchronously and approves or rejects it. You poll the application status

Listing Your Merchants

Merchants you onboard here are also readable through the partner merchant endpoints: GET /partner/api/merchants lists every merchant linked to your partner account, and GET /partner/api/merchants/{merchantId} returns one. Both are documented on the API Onboarding page. Both return merchant identity and company data, with no status. For the application status by merchant, use GET /partner/api/merchants/{merchantId}/application, which reports the lowercase set (created, submitted, approved, and so on), while the endpoints on this page return the full uppercase status below.

Base URL

EnvironmentBase URL
Staginghttps://api.outpostnow.tech
Productionhttps://api.outpostanywhere.com

All endpoints use the /partner/api prefix.

Authentication

All Partner API requests require authentication using a JWT Bearer token provided in the Authorization header.

Request Header

Authorization: Bearer <your_access_api_token>

Key Points

  • Create and manage your API credentials (client ID and client secret) in the Partner Portal
  • You can have up to 2 active API credentials at a time, supporting safe key rotation
  • Include the JWT Bearer token in the Authorization header of every request
  • Keep your API credentials secure - do not expose them in client-side code or public repositories

Example Request

# Include your JWT Bearer token in every request
curl -X GET "https://api.outpostanywhere.com/partner/api/onboarding/applications/{applicationId}" \
  -H "Authorization: Bearer $API_TOKEN"

Initiate Onboarding

POST/partner/api/onboarding/initiate

Creates a new onboarding application for a merchant, or resumes an existing one. This endpoint is idempotent on merchantReference alone: calling it again with the same merchantReference returns the existing application. productCode is not part of the key, so a second call with a different product returns the existing application with its original product. Use a different merchantReference if you need a separate application.

Request Headers

ParameterTypeRequiredDescription
Authorization-YesBearer token for authentication
Content-Type-Yesapplication/json

Request Body Parameters

ParameterTypeRequiredDescription
merchantReferencestringYesYour unique identifier for this merchant
productCodestringYesProduct to onboard for (e.g., tor for Tax of Record)
modestringNoOnboarding mode. Use HOSTED
returnUrlstringNoURL to redirect the merchant after completing hosted onboarding
companyobjectYesMerchant company information
company.legalNamestringYesLegal entity name
company.tradingNamestringNoTrading or brand name
company.websitestringYesCompany website URL
company.taxIdstringYesTax identification number (e.g., VAT number)
company.registrationNumberstringYesCompany registration number
company.jurisdictionstringYesCountry of incorporation (ISO 3166-1 alpha-2)
company.gmvTierstringNoGross Merchandise Volume tier
company.registeredAddressobjectYesRegistered business address
company.registeredAddress.line1stringYesPrimary address line
company.registeredAddress.line2stringNoSecondary address line
company.registeredAddress.citystringYesCity
company.registeredAddress.statestringNoState or province
company.registeredAddress.postalCodestringYesPostal or ZIP code
company.registeredAddress.countrystringYesISO 3166-1 alpha-2 country code
complianceSummaryobjectNoPre-existing compliance data from your KYC process
merchantContextmapNoArbitrary key-value metadata about the merchant

Response 200 OK

{
  "applicationId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "merchantId": "9b1f4c8e-6d2a-4f7b-8e3c-1a5d0f2b7c94",
  "status": "DRAFT",
  "mode": "HOSTED",
  "isExistingApplication": false,
  "onboardingUrl": "https://onboarding.outpostanywhere.com/your-company/onboarding?app=f47ac10b-...&token=..."
}

Response Fields

ParameterTypeRequiredDescription
applicationIdstring-Unique identifier for the onboarding application (UUID)
merchantIdstring-Unique identifier for the merchant Outpost created (UUID). Store it for the merchant-scoped endpoints, such as the tax APIs
statusstring-Current application status
modestring-Onboarding mode (HOSTED)
isExistingApplicationboolean-true if an existing application was returned
onboardingUrlstring-Hosted onboarding URL to redirect the merchant to

Error Responses

HTTPCodeDescription
400invalid_argumentMissing or invalid required company fields

Code Example

curl -X POST "https://api.outpostanywhere.com/partner/api/onboarding/initiate" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantReference": "mrc_123456",
    "productCode": "tor",
    "mode": "HOSTED",
    "returnUrl": "https://your-app.example.com/onboarding/complete",
    "company": {
      "legalName": "Acme Digital Ltd",
      "tradingName": "Acme",
      "website": "https://acme.example",
      "taxId": "GB123456789",
      "registrationNumber": "12345678",
      "jurisdiction": "GB",
      "registeredAddress": {
        "line1": "1 Example Street",
        "city": "London",
        "postalCode": "EC1A 1AA",
        "country": "GB"
      }
    }
  }' | jq

Get Application

GET/partner/api/onboarding/applications/{applicationId}

Returns the current state of an onboarding application. This is the call you poll for the status.

Response Fields

ParameterTypeRequiredDescription
applicationIdstring-Unique identifier (UUID)
merchantIdstring-The Outpost merchant this application belongs to (UUID). Store it for the merchant-scoped endpoints, such as the tax APIs
statusstring-Current status (DRAFT, IN_REVIEW, CHANGES_REQUESTED, APPROVED, SIGNED_BY_MERCHANT, SIGNED_BY_OUTPOST, REJECTED)
modestring-Onboarding mode (HOSTED)
partnerIdstring-Your partner identifier
partnerMerchantReferencestring-The merchantReference you provided at initiation, echoed back. This is your own reference. The Outpost merchant UUID is merchantId above
productCodestring-The productCode you sent at initiation (e.g., tor), echoed back
companyobject-Merchant company information provided at initiation
complianceSummaryobject-The compliance summary you sent at initiation. Absent if you sent none
merchantContextmap-The metadata you sent at initiation. Absent if you sent none
selectedRegionsstring[]-Regions selected by the merchant
businessDescriptionstring-Merchant's business description
storeUrlsstring[]-Merchant's store or checkout URLs
legalRepresentativePartnerContact-The legal representative on the application, with fullName, email and role. Absent until you or the merchant sets one
contactsPartnerContacts-financeContact and technicalContact, each with fullName, email and role. Absent until at least one is set
requiredFieldsstring[]-Fixed list of the fields the flow requires, including legalRepresentative.fullName and legalRepresentative.email. The same list on every application whatever the product, so a mor application lists the legalRepresentative entries too even though only tor requires them. It never shrinks as data is filled in, and it does not tell you what still blocks submission
auditobject-Timestamps for application lifecycle events
audit.createdAtstring-ISO 8601 timestamp when the application was created
audit.updatedAtstring-ISO 8601 timestamp of the last update
audit.submittedAtstring-Timestamp when merchant submitted. Absent until the merchant submits
audit.reviewedAtstring-Timestamp when Outpost reviewed. Absent until Outpost reviews
audit.reviewMessagestring-Reviewer message (e.g., rejection reason, requested changes). Absent until a reviewer writes one

Response 200 OK

{
  "applicationId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "merchantId": "9b1f4c8e-6d2a-4f7b-8e3c-1a5d0f2b7c94",
  "status": "DRAFT",
  "mode": "HOSTED",
  "partnerId": "partner_example",
  "partnerMerchantReference": "mrc_123456",
  "productCode": "tor",
  "company": {
    "legalName": "Acme Digital Ltd",
    "jurisdiction": "GB",
    "...": "..."
  },
  "complianceSummary": {
    "verificationStatus": "VERIFIED",
    "riskLevel": "LOW",
    "countryOfIncorporation": "GB",
    "hasOpenComplianceFlags": false
  },
  "merchantContext": {
    "pspAccountStatus": "ACTIVE"
  },
  "selectedRegions": [
    "GB",
    "DE"
  ],
  "businessDescription": "Subscription software for finance teams",
  "storeUrls": [
    "https://acme.example/checkout"
  ],
  "legalRepresentative": {
    "fullName": "Jane Doe",
    "email": "jane.doe@acme.example",
    "role": "Managing Director"
  },
  "contacts": {
    "financeContact": {
      "fullName": "Frank Smith",
      "email": "finance@acme.example",
      "role": "CFO"
    },
    "technicalContact": {
      "fullName": "Tara Jones",
      "email": "tech@acme.example",
      "role": "CTO"
    }
  },
  "requiredFields": [
    "company.legalName",
    "company.website",
    "company.taxId",
    "company.registrationNumber",
    "company.jurisdiction",
    "company.registeredAddress",
    "company.registeredAddress.line1",
    "company.registeredAddress.city",
    "company.registeredAddress.postalCode",
    "company.registeredAddress.country",
    "legalRepresentative.fullName",
    "legalRepresentative.email"
  ],
  "audit": {
    "createdAt": "2026-03-17T10:00:00Z",
    "updatedAt": "2026-03-17T11:00:00Z"
  }
}

Fields with no value are left out of the response instead of being sent as null. In the example above submittedAt, reviewedAt and reviewMessage are missing because the merchant has not submitted yet. A client that tests value === null will see undefined. Test for a missing key instead.

Error Responses

HTTPCodeDescription
400invalid_argumentThe applicationId in the path is not a valid UUID
404not_foundApplication not found or does not belong to your account

Code Example

curl "https://api.outpostanywhere.com/partner/api/onboarding/applications/{applicationId}" \
  -H "Authorization: Bearer $API_TOKEN" | jq

Update Application

PATCH/partner/api/onboarding/applications/{applicationId}

Updates merchant-editable fields on a draft application. Use this to pre-fill data before the merchant visits the hosted onboarding UI, or to update data after Outpost has requested changes. Only allowed when status is DRAFT or CHANGES_REQUESTED.

Request Body (all fields optional)

ParameterTypeRequiredDescription
selectedRegionsstring[]NoISO 3166-1 alpha-2 country codes for desired regions
businessDescriptionstringNoDescription of the merchant's business
storeUrlsstring[]NoMerchant's store or checkout URLs
categorystringNoBusiness category
legalRepresentativePartnerContactNoThe person authorised to act for the merchant, with fullName, email and role. A tor application cannot be submitted without a non-blank fullName and a valid email. Sending it replaces the whole object, so send every field you want to keep. The merchant fills the same fields in the hosted UI, so what you send here is what they see
contactsPartnerContactsNofinanceContact and technicalContact, each with fullName, email and role. Both optional. Sending contacts replaces the pair, so send both together; leaving contacts out keeps them as they are

Returns the full application state (same structure as Get Application).

Error Responses

HTTPCodeDescription
400invalid_argumentThe applicationId in the path is not a valid UUID, or a contact email is not a valid address. The body names the field, for example legalRepresentative.email. Nothing in the request is stored
404not_foundApplication not found or does not belong to your account
409invalid_statusApplication is not in DRAFT or CHANGES_REQUESTED status

Code Example

curl -X PATCH "https://api.outpostanywhere.com/partner/api/onboarding/applications/{applicationId}" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "selectedRegions": ["GB", "DE", "FR"],
    "businessDescription": "SaaS platform for finance teams",
    "storeUrls": ["https://acme.example/checkout"],
    "legalRepresentative": {
      "fullName": "Jane Doe",
      "email": "jane.doe@acme.example",
      "role": "Managing Director"
    },
    "contacts": {
      "financeContact": {
        "fullName": "Frank Smith",
        "email": "finance@acme.example",
        "role": "CFO"
      },
      "technicalContact": {
        "fullName": "Tara Jones",
        "email": "tech@acme.example",
        "role": "CTO"
      }
    }
  }' | jq

Application Status Lifecycle

Onboarding applications progress through these statuses. Regenerate Link is blocked once the application reaches APPROVED, SIGNED_BY_OUTPOST or REJECTED. APPROVED is not the end of the line: Outpost can still move an approved application back to CHANGES_REQUESTED.

Poll for status changes: there are no webhooks

Outpost does not call you back when a status changes. Poll GET /partner/api/onboarding/applications/{applicationId} on a slow schedule and stop once the status is APPROVED, SIGNED_BY_OUTPOST or REJECTED. An ops manager reviews each application, so the outcome takes as long as it takes.

Status Transitions

DRAFT
  │  merchant submits
  ▼
IN_REVIEW ──[Outpost rejects]──> REJECTED
  │  Outpost approves
  ▼
APPROVED ──[merchant signs]──> SIGNED_BY_MERCHANT
                                       │  Outpost counter-signs
                                       ▼
                               SIGNED_BY_OUTPOST

Outpost can send an application back for changes from
IN_REVIEW, APPROVED or SIGNED_BY_MERCHANT:

  CHANGES_REQUESTED ──[merchant resubmits]────> IN_REVIEW
        │
        └──[Outpost decides]──> APPROVED or REJECTED

Statuses

StatusDescription
DRAFTApplication created but not yet submitted by the merchant
IN_REVIEWMerchant has submitted, Outpost is reviewing
CHANGES_REQUESTEDOutpost requested changes, and the merchant can update and resubmit
APPROVEDApplication approved by Outpost. Outpost can still move it back to CHANGES_REQUESTED
SIGNED_BY_MERCHANTThe merchant has signed the Outpost agreement; Outpost has not counter-signed yet
SIGNED_BY_OUTPOSTOutpost has counter-signed the agreement; the merchant is onboarded
REJECTEDApplication rejected by Outpost

Who Triggers Each Transition

TransitionTriggered By
DRAFT → IN_REVIEWMerchant, via the hosted onboarding UI
IN_REVIEW → APPROVEDOutpost operations team
IN_REVIEW → REJECTEDOutpost operations team
IN_REVIEW → CHANGES_REQUESTEDOutpost operations team
CHANGES_REQUESTED → IN_REVIEWMerchant, via the hosted onboarding UI
CHANGES_REQUESTED → APPROVEDOutpost operations team
CHANGES_REQUESTED → REJECTEDOutpost operations team
APPROVED → CHANGES_REQUESTEDOutpost operations team
APPROVED → SIGNED_BY_MERCHANTMerchant, by signing the Outpost agreement. Signing happens in the Outpost merchant dashboard after approval, not in the hosted onboarding form.
SIGNED_BY_MERCHANT → SIGNED_BY_OUTPOSTOutpost operations team
SIGNED_BY_MERCHANT → CHANGES_REQUESTEDOutpost operations team

What You Should Do at Each Status

StatusYour Action
DRAFTWait for the merchant to visit the hosted URL and submit. Optionally pre-fill data via PATCH.
IN_REVIEWNo action needed. Wait for Outpost review.
CHANGES_REQUESTEDNotify the merchant. Check audit.reviewMessage for details. Regenerate the link if expired.
APPROVEDMerchant is approved. Proceed with activation in your system. Keep polling: Outpost can still request changes.
SIGNED_BY_MERCHANTNo action needed. Wait for Outpost to counter-sign the agreement.
SIGNED_BY_OUTPOSTThe agreement is signed by both sides. The merchant is onboarded.
REJECTEDNotify the merchant. Check audit.reviewMessage for the reason.

Data Models

Reference for the data structures used in onboarding API requests and responses.

OnboardingCompany

ParameterTypeRequiredDescription
legalNamestringYesLegal entity name
tradingNamestringNoTrading or brand name
websitestringYesCompany website URL
taxIdstringYesTax identification number
registrationNumberstringYesCompany registration number
jurisdictionstringYesCountry of incorporation (ISO 3166-1 alpha-2)
gmvTierstringNoGross Merchandise Volume tier
registeredAddressOnboardingAddressYesRegistered business address

OnboardingAddress

ParameterTypeRequiredDescription
line1stringYesPrimary address line
line2stringNoSecondary address line
citystringYesCity
statestringNoState or province
postalCodestringYesPostal or ZIP code
countrystringYesISO 3166-1 alpha-2 country code

PartnerContact

Used for the legal representative and for both entries under contacts.

ParameterTypeRequiredDescription
fullNamestringNoThe person’s full name
emailstringNoEmail address. Rejected with 400 invalid_argument if it is not a valid address
rolestringNoJob title, for example Managing Director. Free text

PartnerContacts

ParameterTypeRequiredDescription
financeContactPartnerContactNoWho to contact about tax filings and invoices
technicalContactPartnerContactNoWho to contact about the integration

PartnerComplianceSummary

ParameterTypeRequiredDescription
verificationStatusstringNoYour verification status for this merchant
riskLevelstringNoYour risk assessment level
countryOfIncorporationstringNoCountry of incorporation from your records
hasOpenComplianceFlagsbooleanNoWhether there are open compliance flags

OnboardingGmvTier

ValueDescription
UP_TO_100KUp to $100K annual GMV
FROM_100K_TO_250K$100K to $250K
FROM_250K_TO_500K$250K to $500K
FROM_500K_TO_1M$500K to $1M
FROM_1M_TO_10M$1M to $10M
FROM_10M_TO_50M$10M to $50M
FROM_50M_TO_100M$50M to $100M
FROM_100M_TO_250M$100M to $250M
FROM_250M_TO_500M$250M to $500M
FROM_500M_TO_1B$500M to $1B

PartnerAuditResponse

ParameterTypeRequiredDescription
createdAtstring-ISO 8601 timestamp when the application was created
updatedAtstring-ISO 8601 timestamp of the last update
submittedAtstring-Timestamp when the merchant submitted. Absent until the merchant submits
reviewedAtstring-Timestamp when Outpost reviewed. Absent until Outpost reviews
reviewMessagestring-Reviewer's message (e.g., rejection reason, requested changes). Absent until a reviewer writes one

Error Handling

All error responses follow a consistent structure with a category code and field-specific error details.

Error Response Format

{
  "code": "invalid_argument",
  "errors": [
    {
      "field": "company.legalName",
      "message": "required"
    }
  ]
}

Error Codes

CodeDescription
invalid_argumentOne or more request fields are invalid or missing
not_foundThe requested application was not found or does not belong to your account
invalid_statusThe application is not in a status that allows the requested operation
terminal_statusThe application is APPROVED, SIGNED_BY_OUTPOST or REJECTED, so Regenerate Link cannot issue a new link

Common Error Scenarios

ScenarioStatusCodeResolution
Missing required company fields at initiation400invalid_argumentInclude all required fields in the company object
Application not found404not_foundVerify the applicationId and ensure it belongs to your account
Updating an application in review409invalid_statusYou can only update applications in DRAFT or CHANGES_REQUESTED status
Path applicationId is not a valid UUID400invalid_argumentSend the applicationId exactly as returned by Initiate Onboarding
Regenerating a link for a signed-off application409terminal_statusNo new link can be issued once the application is APPROVED, SIGNED_BY_OUTPOST or REJECTED. Create a new application if needed

Required Fields for Submission

Before the merchant can submit the application in the hosted UI, these fields must be filled (by the merchant or pre-filled by you via PATCH). The check runs only for the tor product. The field names below are the keys the error reports, which are not always the same as the request field names.

Reported fieldDescription
productsNo product is selected on the application. This is reported on its own, in place of the fields below
selectedRegionsAt least one region must be selected
businessDescriptionBusiness description must be provided
checkoutUrlAt least one store or checkout URL must be provided. Set it with the storeUrls field on Update Application
legalRepresentativeA legal representative must have a non-blank fullName and a valid email. The merchant enters this in the hosted UI, and you can pre-fill it on Update Application

None of the four endpoints on this page returns this error. Submission happens in the hosted UI, which returns incomplete_application to the merchant. The API-mode onboarding endpoints return it too.