Lead Posting API
Send consumer leads into the Pennie distribution network. The engine evaluates each lead in real time and returns matched offers from active bidding partners.
Base URL
Base URLs are partner-specific and provided directly by Pennie during onboarding. All endpoint paths in this document are relative to your assigned base URL.
https://<partner>.trypennie.dev
Full Endpoint URLs
https://<partner>.trypennie.dev/tokenhttps://<partner>.trypennie.dev/biddingAuthentication
This API uses the OAuth 2.0 Client Credentials flow. Credentials are partner-specific and issued by Pennie at onboarding.
-
Request a token
Call
POST /tokenwith yourclient_idandclient_secretencoded as HTTP Basic credentials. -
Receive a Bearer token
The response includes an
access_tokenvalid for 3600 seconds (1 hour). -
Attach to every request
Include the token in the
Authorizationheader on all calls to/bidding.
POST /token
Exchange client credentials for a Bearer access token.
Pass your credentials as an HTTP Basic Authorization header.
The grant_type query parameter must be set to client_credentials.
https://<partner>.trypennie.dev/token
Headers
Basic <Base64(client_id:client_secret)>Query Parameters
client_credentialsExample Request
curl -X POST "https://<partner>.trypennie.dev/token?grant_type=client_credentials" \ -H "Authorization: Basic $(echo -n 'client_id:client_secret' | base64)"
Response — 200 OK
{
"access_token": "at_0ef932a01d9303d4c7fc07b8a650...",
"expires_at": 1753214916,
"expires": 3600,
"token_type": "Bearer"
}
3600.Bearer.POST /bidding
Submit a consumer lead into the Pennie distribution network and receive matched offers in real time.
Requires a valid Bearer token in the Authorization header obtained from /token.
https://<partner>.trypennie.dev/bidding
leadId1–leadId4
are partner-specific. Pennie will confirm your required identifiers during onboarding.
Headers
Bearer <access_token>application/jsonTracking Identifiers PARTNER-SPECIFIC
personalInformation required
^\d{10}$PA CA TX^\d{5}$YYYY-MM-DD Example: 1985-07-22^\d{9}$loanInformation required
1000mortgageInformation required
creditInformation required
financialInformation required
educationInformation optional
legalInformation required
true.true.sessionInformation required
Example Request Body
{
"leadId1": "lead_550e8400e29b41d4a716",
"leadId2": "pub_abc123",
"leadId3": "sub_source_xyz",
"leadId4": "creative_001",
"personalInformation": {
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"city": "Philadelphia",
"state": "PA",
"primaryPhone": "2155550123",
"address1": "123 Main Street",
"address2": "Apt 4B",
"zipcode": "19103",
"dateOfBirth": "1985-07-22",
"ssn": "123456789"
},
"loanInformation": {
"purpose": "debt_consolidation",
"loanAmount": 15000
},
"mortgageInformation": {
"propertyStatus": "rent"
},
"creditInformation": {
"providedCreditRating": "good"
},
"financialInformation": {
"employmentStatus": "employed_full_time",
"employmentPayFrequency": "biweekly",
"annualIncome": 65000
},
"educationInformation": {
"educationLevel": "bachelors"
},
"legalInformation": {
"consentsToFcra": true,
"consentsToTcpa": true
},
"sessionInformation": {
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
}
Responses
Lead accepted. Returns a list of matched offers. An empty offers array means no bids matched.
{
"requestId": "req_abc123xyz",
"offers": [
{
"name": "partner_lender_a",
"display_name": "Lender A",
"rate": 12.5,
"click_url": "https://example-lender.com/apply?ref=pennie",
"product_type": "personal_loan",
"logo_src": "https://cdn.trypennie.com/logos/lender_a.png",
"offer_title": "Personal Loan up to $20,000",
"offer_details":"Fixed rate. No prepayment penalty."
}
]
}Lead failed validation or eligibility rules. Returned as HTTP 200 with a rejected status. The reason field contains a machine-readable rejection code.
{
"lead_id": "30F7wmobcOeKg9Xe4h13k19rDr8",
"status": "rejected",
"reason": "invalid_state"
}Missing or invalid Bearer token. Request a new token via /token and retry.
{
"status": "error",
"reason": "unauthorized"
}Internal server error. Retry with exponential backoff. Contact Pennie support if the issue persists.
{
"lead_id": "30F7wmobcOeKg9Xe4h13k19rDr8",
"status": "error",
"reason": "internal server error"
}POST /completed-sale
Notify Pennie that a sale has been completed for an offer, and confirm whether that offer is still eligible.
Call this endpoint when a consumer completes a sale on one of the offers returned by /bidding.
The response indicates whether the lead's offer is still eligible (accepted) or
not (rejected, with a machine-readable rejection_reason). Authenticate with the same
Bearer token used for /bidding.
https://<partner>.trypennie.dev/completed-sale
Headers
Bearer <access_token> — the token returned by /token.application/jsonRequest Body
Each offer in the
/bidding response includes a click_url (offers[].click_url).
The Pennie Lead ID is the last path segment of that URL. You may send either the full URL or just the ID.
For example, a
click_url of
https://trypennie.com/offerportal/a06Ui00002Qm3QFFF would be sent as
a06Ui00002Qm3QFFF (or you may pass the entire URL).
Example Request
curl -X POST "https://<partner>.trypennie.dev/completed-sale" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{ "pennie_lead_id": "a06Ui00002Qm3QFFF" }'
Example Request Body
{
"pennie_lead_id": "a06Ui00002Qm3QFFF"
}
Responses
The offer is still eligible. The sale has been recorded.
{
"status": "accepted"
}The offer is no longer eligible. Returned as HTTP 200 with a rejected status. The rejection_reason field contains a machine-readable code (e.g. bid_timeout).
{
"status": "rejected",
"rejection_reason": "bid_timeout"
}Missing or invalid Bearer token. Request a new token via /token and retry.
{
"status": "error",
"reason": "unauthorized"
}Tracking Identifiers
The four tracking identifier fields (leadId1–leadId4) map to campaign-specific values confirmed by Pennie at onboarding.
Enum Reference
All accepted values for enumerated fields.
Response Codes
status: "rejected" and a machine-readable reason code./token.Try It
Test the API against a sandbox endpoint using the dummy credentials below. No real data is submitted.
https://test-api.trypennie.dev
/token call:client_id: test_client_pennie
client_secret: test_secret_pennie
Step 1 — Get a Token
Step 2 — Submit a Lead
{}