Track a Signup
Call /v1/evaluate/signup when a customer creates an account on your site. Pinch evaluates the new identity against historical patterns and emits a decision: APPROVE (let the account through), DECLINE (block the signup), or REVIEW (queue for manual approval).
Most fields below are optional but improve accuracy. At minimum you need a stable customerId, an email, and the device fingerprint if you've installed the JS SDK.
Request
POST /v1/evaluate/signup HTTP/1.1
Host: api.pinch.ai
Authorization: {api-key}
Content-Type: application/json
Body
| Field | Type | Required | Description |
|---|---|---|---|
customerId | string | yes | Your platform's stable identifier for this customer. |
firstName | string | yes | Customer's first name. |
lastName | string | yes | Customer's last name. |
username | string | yes | Login username — often the email. |
website | string | no | Domain where the signup happened. Useful when a single Pinch account serves multiple stores. |
referralCodeApplied | string | no | Referral code the signup used, if any. |
referrerID | string | no | customerId of the referring customer. |
referralID | string | no | Your own referral campaign identifier. |
contactInformation | array | yes | Array of contact entries (see below). |
deviceFingerprints | array | recommended | [{ "deviceIdentifier": "{visitorId}" }]. Strongly recommended. |
Contact information
Each contactInformation entry has a contactType of ContactAddress, EMail, or Phone. Send at least one EMail. Address and phone improve accuracy substantially.
EMail—{ "contactType": "EMail", "address": "user@example.com" }Phone—{ "contactType": "Phone", "number": "+1-555-123-4567" }ContactAddress—{ "contactType": "ContactAddress", "address": { line1, line2, city, state, postalCode, country, geoCode: { longitude, latitude } }, "addressType": "Business" | "Shipping" | "Billing" }
Example request
- curl
- Node
- Python
curl https://api.pinch.ai/v1/evaluate/signup \
-H "Authorization: $PINCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customerId": "user_12345abcde",
"firstName": "John",
"lastName": "Doe",
"username": "johndoe@example.com",
"website": "https://www.demostore.com",
"contactInformation": [
{
"contactType": "ContactAddress",
"address": {
"line1": "1234 Main St",
"line2": "Suite 500",
"city": "San Francisco",
"state": "CA",
"postalCode": "94101",
"country": "US"
},
"addressType": "Business"
},
{ "contactType": "EMail", "address": "johndoe@example.com" },
{ "contactType": "Phone", "number": "+1-555-123-4567" }
],
"deviceFingerprints": [
{ "deviceIdentifier": "abc123visitorId" }
]
}'
const res = await fetch("https://api.pinch.ai/v1/evaluate/signup", {
method: "POST",
headers: {
Authorization: process.env.PINCH_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
customerId: "user_12345abcde",
firstName: "John",
lastName: "Doe",
username: "johndoe@example.com",
website: "https://www.demostore.com",
contactInformation: [
{ contactType: "EMail", address: "johndoe@example.com" },
{ contactType: "Phone", number: "+1-555-123-4567" },
],
deviceFingerprints: [{ deviceIdentifier: visitorId }],
}),
});
const decision = await res.json();
import os, requests
res = requests.post(
"https://api.pinch.ai/v1/evaluate/signup",
headers={
"Authorization": os.environ["PINCH_API_KEY"],
"Content-Type": "application/json",
},
json={
"customerId": "user_12345abcde",
"firstName": "John",
"lastName": "Doe",
"username": "johndoe@example.com",
"contactInformation": [
{"contactType": "EMail", "address": "johndoe@example.com"}
],
"deviceFingerprints": [{"deviceIdentifier": visitor_id}],
},
)
decision = res.json()
Response
{
"providerSignupID": "user_12345abcde",
"pinchSignupID": "psgn_4a8c1f9e",
"Decisions": [
{
"decisions": [
{
"decisionType": "APPROVE/DECLINE",
"decision": "APPROVE",
"subDecision": "Default Approve",
"decisionReason": "No risk signals detected",
"abuseScore": 8
}
]
}
]
}
| Field | Description |
|---|---|
providerSignupID | Echo of your customerId. |
pinchSignupID | Pinch's internal identifier for this signup event. |
Decisions[].decisions[].decision | APPROVE, DECLINE, or REVIEW. |
Decisions[].decisions[].subDecision | The workflow branch that matched. |
Decisions[].decisions[].decisionReason | Human-readable explainer. |
Decisions[].decisions[].abuseScore | 0–100 risk score. |
Decision semantics
| Decision | Recommended action |
|---|---|
APPROVE | Create the account normally. |
DECLINE | Block the signup. Show a generic error rather than calling out fraud detection — don't tip off bad actors. |
REVIEW | Create the account in a "pending verification" state. Require email + phone verification, or queue for manual approval. |
Common abuse patterns detected at signup
- Multi-account abuse — a single device, IP, or address creating multiple accounts to chain new-customer promotions
- Disposable email signups — accounts created on throwaway domains, often paired with prepaid cards
- Referral fraud — fake referrals to extract bonus credits, especially when
referrerIDis set and the referrer's behavior is also abusive - Bot signups — devices that have created accounts at suspiciously high velocity
Errors
See Errors for the full envelope. Endpoint-specific codes:
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Required field missing |
| 409 | duplicate_customer | customerId already exists |
| 422 | unprocessable_entity | Field values failed validation |
| 429 | rate_limited | Slow down |
See also
- Login API — track every login attempt
- Authentication — API key setup