Quote Request API

Longship Junk Removal of Levittown · Levittown, PA · levittownlongshipjunk.com

This API submits a junk-removal quote request. It is the same endpoint the quote form on this site posts to. Everything here is discoverable from /.well-known/api-catalog (RFC 9727), and described formally in the OpenAPI 3.1 document.

A 200 does not mean the request was delivered. Read the mail field in the response. "sent" means the office was notified. "skipped" means the submission was classified as automated and quarantined — it is stored, but nobody is notified and nobody will call back. The usual cause is a missing or too-recent t0. See Getting past the automation filter.

Before you submit on someone's behalf

A real person calls or texts the number you send. Only submit for someone who asked you to and who has agreed to be contacted about it. Every submission stores a consent record — the exact consent wording, its version, and a timestamp — against that phone number. What is collected and who receives it is set out in the privacy policy.

Endpoints

MethodPathPurpose
POST/wp-json/lsj/v1/leadSubmit a quote request
GET/wp-json/lsj/v1/healthService health

Authentication

None — this is a public, anonymous quote form. Do not send an Origin header unless it is this site's own origin; a foreign Origin is rejected with 403. Server-to-server callers that send no Origin at all are accepted.

Getting past the automation filter

The endpoint quarantines submissions that look scripted. One field decides it:

FieldWhat to send
t0Epoch milliseconds marking when you began preparing the request. It must be at least 3 000 ms in the past and less than 6 hours old when you submit. rendered_at is an accepted alias.
js"1". Kept for parity with the browser form.

This is not a hoop to jump through — it is the honest value. If you gathered the customer's name, number and job description in a conversation, that conversation started well over three seconds ago. Stamp t0 when you start collecting, not when you send.

Fields

FieldReq.Notes
nameyes2–80 characters. A URL anywhere in it is rejected.
phoneyes10–15 digits once non-digits are stripped. US numbers are normalised to E.164.
t0yesSee above. Omit it and the request is quarantined.
emailnoOptional, but an invalid address fails the request rather than being ignored.
zipno5-digit ZIP, or a town name if the ZIP is unknown.
townnoTown, when sent separately from zip.
detailsnoUp to 2 000 characters. The most useful field for an accurate quote — what the items are, which floor, and whether there are stairs.
besttimenoPreferred callback window, free text.
discountnoSet when the customer is a senior or a veteran — flags the standing 10% discount.
sidnoIdempotency key. Replaying the same value within 10 minutes returns the original response and creates no second record. Send one on every retry.
sourcenoIdentify your client here so the operator can tell agent-submitted requests apart.
photosnoUp to 5 files, 10 MB each, 25 MB per batch. JPEG, PNG, WEBP, HEIC. Type is read from the bytes, not the filename. Requires multipart/form-data.

Example

curl -X POST https://levittownlongshipjunk.com/wp-json/lsj/v1/lead \
  -F "name=Maria Delgado" \
  -F "phone=(267) 555-0142" \
  -F "zip=19055" \
  -F "details=Sectional couch and a dead chest freezer, basement, one flight up." \
  -F "discount=1" \
  -F "source=ai-assistant" \
  -F "sid=$(uuidgen)" \
  -F "js=1" \
  -F "t0=$(( $(date +%s) * 1000 - 8000 ))"

A delivered request:

{
  "ok": true,
  "photos_saved": 0,
  "photos_failed": 0,
  "photo_errors": [],
  "mail": "sent"
}

Errors

Errors use the standard WordPress REST envelope: code, message, and a data object carrying status.

StatusCodeMeaning
400lsj_invalidValidation failed. data.fields maps each bad field to a message you can show the customer.
403lsj_bad_originA cross-origin Origin header was sent.
413lsj_too_largeThe whole POST body exceeded the server limit — the photos were too big.
429lsj_rate_limited5 submissions per IP per 15 minutes.
500lsj_store_failedNothing was stored. Retry, or call.

Partial success

Photos never cost you the request. The text record is committed before any image data is read, and each photo is attached individually — so a failure on photo 4 keeps photos 1–3 and the whole record. Check photos_failed and photo_errors; a non-empty photo_errors with mail: "sent" is still a delivered request.

Rate limits

5 submissions per IP per 15 minutes, returned as 429. Site-wide, above 40 submissions an hour the endpoint degrades rather than refusing: the text is still stored and delivered, and photos are skipped with a note in photo_errors.

Read-only content

Pages, posts and service-area content are readable through the standard WordPress REST API at /wp-json/wp/v2. Its routes and schemas are listed at /wp-json/. Quote records are private and are not exposed there.

If this API is not the right fit

Call (267) 609-9327. The phone is answered 24/7 — by a person during the day, and after hours by an automated assistant that identifies itself as automated. Answering 24/7 is not the same as hauling 24/7; crews run during working hours.