{"components":{"schemas":{"Balance":{"properties":{"account_email":{"type":"string"},"available_cents":{"type":"integer"},"funded_cents":{"type":"integer"},"held_cents":{"type":"integer"},"spent_cents":{"type":"integer"},"topup_min_cents":{"example":2500,"type":"integer"},"topup_presets_cents":{"items":{"type":"integer"},"type":"array"},"unit_price_cents":{"type":"integer"}},"type":"object"},"Error":{"properties":{"available_cents":{"type":"integer"},"code":{"description":"Stable machine-readable code","type":"string"},"error":{"description":"Customer-safe message","type":"string"},"needed_cents":{"type":"integer"},"upload_status":{"type":"string"}},"required":["error","code"],"type":"object"},"Job":{"properties":{"billable_units":{"type":"integer"},"completed_at":{"nullable":true,"type":"string"},"created_at":{"type":"string"},"download_url":{"description":"Present when complete","type":"string"},"error":{"nullable":true,"type":"string"},"final_cents":{"nullable":true,"type":"integer"},"id":{"type":"integer"},"idempotency_key":{"nullable":true,"type":"string"},"input_rows":{"type":"integer"},"original_filename":{"nullable":true,"type":"string"},"price_version":{"type":"string"},"reserved_cents":{"type":"integer"},"retention_until":{"nullable":true,"type":"string"},"service":{"example":"dnc","type":"string"},"status":{"enum":["reserving","rejected","queued","running","complete","failed"],"type":"string"},"status_url":{"description":"Private status page","type":"string"},"summary":{"$ref":"#/components/schemas/JobSummary"},"unit_price_cents":{"type":"integer"},"updated_at":{"type":"string"},"upload_status":{"nullable":true,"type":"string"}},"type":"object"},"JobSummary":{"description":"Present once the job is complete","properties":{"blank_phone_cells":{"type":"integer"},"cache_hits":{"type":"integer"},"invalid_phone_cells":{"type":"integer"},"no_match_phones":{"type":"integer"},"registry_match_phones":{"type":"integer"},"rows":{"type":"integer"},"unique_valid_phones":{"type":"integer"}},"type":"object"},"LedgerEntry":{"properties":{"amount_cents":{"description":"Signed balance delta","type":"integer"},"created_at":{"type":"string"},"external_ref":{"nullable":true,"type":"string"},"id":{"type":"integer"},"job_id":{"nullable":true,"type":"integer"},"kind":{"enum":["topup","promo","reserve","finalize","release","adjust"],"type":"string"},"reason":{"nullable":true,"type":"string"},"usage_cents":{"description":"On finalize rows: what the job actually cost","nullable":true,"type":"integer"}},"type":"object"},"Quote":{"properties":{"available_cents":{"type":"integer"},"billable_units":{"description":"Unique valid phone numbers","type":"integer"},"input_rows":{"type":"integer"},"max_unique":{"example":10000,"type":"integer"},"total_cents":{"type":"integer"},"unit_price_cents":{"example":10,"type":"integer"},"upload_status":{"type":"string"},"upload_token":{"type":"string"}},"type":"object"},"Upload":{"properties":{"expires_at":{"format":"date-time","type":"string"},"headers":{"items":{"type":"string"},"type":"array"},"phone_fields":{"items":{"type":"string"},"type":"array"},"quote":{"properties":{"amount":{"description":"Pay-per-file price incl. minimum; not the balance price","type":"number"},"minimum":{"type":"number"},"price_per_phone":{"type":"number"},"unique_valid_phones":{"type":"integer"}},"type":"object"},"row_count":{"type":"integer"},"status":{"enum":["analyzed","needs_mapping","needs_custom","checkout_pending","paid","queued","running","complete","failed","expired"],"type":"string"},"suggested_fields":{"items":{"type":"string"},"type":"array"},"token":{"type":"string"}},"type":"object"}},"securitySchemes":{"bearerAuth":{"description":"Your access key, e.g. Authorization: Bearer llt_xxxxxxxx_... . Issued by email on your first top-up; rotate it in the portal (the old key stops at once).","scheme":"bearer","type":"http"}}},"info":{"contact":{"name":"LeadLoom","url":"https://leadloom.thewoob.com/contact"},"description":"Screen your own phone lists against the National Do Not Call Registry from a prepaid balance. Billing is $0.10 per unique valid phone number, held when a job starts and charged when it completes; a failed job is never charged. Every original row is returned with result columns appended. Funding and access keys are managed in the portal at https://leadloom.thewoob.com/tools; human-readable reference at https://leadloom.thewoob.com/tools/docs.","termsOfService":"https://leadloom.thewoob.com/terms","title":"LeadLoom Tools API","version":"1"},"openapi":"3.0.3","paths":{"/api/dnc-upload/analyze":{"post":{"description":"Multipart upload of one CSV or XLSX (max 20 MB, 50,000 rows). Detects phone columns, normalizes numbers and counts unique valid phones. Returns an upload token used by every later call. The quote.amount here includes the per-file minimum of the pay-per-file product; balance-funded jobs have no per-file minimum, so price them with /api/tools/v1/dnc/quote instead.","requestBody":{"content":{"multipart/form-data":{"schema":{"properties":{"file":{"format":"binary","type":"string"}},"required":["file"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}},"description":"Analyzed upload"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"file_required or a validation error"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"file_too_large"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"rate_limited"}},"security":[],"summary":"Upload and analyze a file","tags":["upload"]}},"/api/dnc-upload/{token}/download":{"get":{"description":"UTF-8 CSV with a byte-order mark so Excel opens it cleanly. Every original row and column is preserved; for each phone column four columns are appended: <field> Normalized, <field> DNC Result, <field> DNC Checked At, <field> DNC Source. Authorized by the unguessable upload token. Deleted 30 days after upload.","parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"result not found"}},"security":[],"summary":"Download the result CSV","tags":["jobs"]}},"/api/dnc-upload/{token}/mapping":{"post":{"description":"Re-analyze with explicit phone columns when status is needs_mapping.","parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"phone_fields":{"example":["Phone","Mobile"],"items":{"type":"string"},"type":"array"}},"required":["phone_fields"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}},"description":"Re-analyzed upload"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"invalid_phone_mapping"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"not_found"}},"security":[],"summary":"Choose the phone columns","tags":["upload"]}},"/api/tools/v1/balance":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}},"description":"Balance"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"unauthorized"}},"summary":"Balance for the key's account","tags":["account"]}},"/api/tools/v1/dnc/jobs":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/Job"},"type":"array"}},"type":"object"}}},"description":"Jobs"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"unauthorized"}},"summary":"List your jobs, newest first","tags":["jobs"]},"post":{"description":"Holds billable_units x unit_price_cents from the balance and queues the job. Send an idempotency_key you generate per intended job: a retry with the same key returns the same job (200) instead of holding money twice, and a refused job replays as the same refusal. One upload token can be bound to one job.","requestBody":{"content":{"application/json":{"schema":{"properties":{"idempotency_key":{"maxLength":120,"type":"string"},"upload_token":{"type":"string"}},"required":["upload_token"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}},"description":"Idempotent replay of an existing job"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}},"description":"Job created and queued"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"upload_token_required or nothing_to_bill"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"insufficient_scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"not_found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"insufficient_balance (with available_cents and needed_cents), upload_not_ready (with upload_status) or needs_custom"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"rate_limited"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"screening_unavailable or provider_capacity"}},"summary":"Start a screening job from your balance","tags":["jobs"]}},"/api/tools/v1/dnc/quote":{"get":{"parameters":[{"in":"query","name":"upload_token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}},"description":"Server-side price"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"upload_token_required"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"not_found"}},"summary":"Price an analyzed upload against your balance","tags":["jobs"]}},"/api/tools/v1/jobs/{id}":{"get":{"description":"Poll every few seconds until status is complete or failed. download_url appears when the result is ready.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}},"description":"Job"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"not_found"}},"summary":"Poll one job","tags":["jobs"]}},"/api/tools/v1/usage":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"entries":{"items":{"$ref":"#/components/schemas/LedgerEntry"},"type":"array"}},"type":"object"}}},"description":"Ledger"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"unauthorized"}},"summary":"Ledger entries, newest first","tags":["account"]}}},"security":[{"bearerAuth":[]}],"servers":[{"url":"https://leadloom.thewoob.com"}],"tags":[{"description":"Store and analyze a CSV or XLSX file (no key required).","name":"upload"},{"description":"Quote, start and track balance-funded screening jobs.","name":"jobs"},{"description":"Balance and ledger for the key's account.","name":"account"}],"x-result-labels":["Registry match","No registry match found","Invalid number","Not checked"]}
