Heads up: Our Discord server was banned. We've moved — join the new one to keep using the bots.Join New Server →

DoorDash API

Everything the Discord bot does — account generation, the 50%-off deal, preview, and ordering — exposed as a REST API you fully control. Build your own bot, website, dashboard, or automation on the same engine, and customize every detail of every order.

Overview

The DoorDash API lets you build your own tools on top of AutoMunch's DoorDash engine. You generate accounts into named batches, the API automatically flags which ones have the 50%-off deal, and you place orders against them. Orders are session-based: order by account_id and the server uses the account's stored login — you never handle raw tokens.

Base URL

https://automunch.site/dd

Subscribers only

The DoorDash API requires an active DoorDash subscription (Tier I/II/III or Lifetime). Generate your key with /api_key in the AutoMunch Discord.

What's built in

50% DashPass OR 40% promo (mutually exclusive — combining a DashPass deal with a promo code is no longer accepted by DoorDash), price-before-you-charge previews, Express & Scheduled delivery, an automatic public tracking link on every order, optional address-swap, and custom carts from the browser extension (automunch.site/cart/...). Failed orders never charge credits.

Discord-only features

No /multiorder-equivalent and no /string endpoint — those are Discord-only. Use multiple /v1/order calls (cap: 2 active jobs).

Under the hood

The engine talks to DoorDash's Android mobile API (not the web site) with client id 1679956685075657170. Signup reCAPTCHA runs through CapMonster V3 Enterprise as a fallback (NextCaptcha broke for mobile reCAPTCHA on 2026-09-22, so acceptance under the fallback is lower than it used to be — expect retries on mode: "signup"). /v1/gen traffic goes out over a dedicated ET Mobile 4G pool; /v1/order and scrape traffic use the main ET Mobile pool. Every login-mode order submits a full Riskified fingerprint on each attempt — required since the 2026-09-23 fix to clear tap/3DS/dyscan declines.

Authentication

Every request needs a Bearer token in the Authorization header. AutoMunch API keys are prefixed with am_live_ (unified across every AutoMunch bot — the same key works for DoorDash, Uber Eats, Instacart, etc.) and are generated with /api_key on Discord. One active key per user. Legacy dd_live_ keys from before the unified-wallet migration are still accepted.

Authorization Header
Authorization: Bearer am_live_your_key_here
Settings come from Discord

Your SMS key, email domain, and List tier are read from your /settings on Discord (linked to your key). Run /settings once before using /v1/gen. Without a saved daisysms_api_key in /settings, POST /v1/gen returns 400 daisysms_api_key not configured. Default List tier is now DDPublic.

The 50% Deal

50% off is DashPass-only — not a combo. Every order lands in exactly one of two buckets: the 50% DashPass deal (no promo code) or a 40% promo code (no DashPass deal). The two are mutually exclusive. The old combo that layered a promo code on top of the DashPass deal is dead — DoorDash stopped allowing a promo to apply alongside the DashPass deal, so the bot picks whichever single path saves more on the cart.

What the deal actually is. The 50% deal is DoorDash's UPSELL_OFFER_TYPE_DEALSPROMO tied to a DashPass free-trial audience (CLASSIC_FREE_TRIAL / RESURRECTED_FREE_TRIAL). It is not a code — it is an audience-targeted free-trial offer DoorDash shows to some accounts. Subscribing the free trial commits a PROMOTION_DISCOUNT line onto the cart. It is region/history/cart-sensitive, and DoorDash only surfaces it on carts over a ~$15 subtotal floor.

Card-free trial. The bot subscribes the free DashPass trial with stripe_id: "" — no payment method is attached, so the trial physically cannot auto-charge the $9.99 when it would otherwise expire. Any pre-existing trial on the account is cancelled before the card is added so DoorDash cannot auto-link the newly-tokenized card to a lingering subscription, and a retry-cancel runs after the order lands (see Confirm & Place).

How accounts get flagged. On POST /v1/gen the engine runs the heavy probe: it builds a throwaway probe cart over the ~$15 floor, confirms the UPSELL_OFFER_TYPE_DEALSPROMO upsell, subscribes the free DashPass trial card-free, verifies a real committed PROMOTION_DISCOUNT line, then marks the account is_50_eligible: true. The /scrape command on Discord uses a light probe that sets the eligibility flag from the upsell signal without subscribing the trial. The badge means "last probe saw the deal on offer," not a permanent guarantee.

Freshness & one-shot

The free-trial deal can lapse as an account ages, so every eligible account carries a checked_at timestamp and a stale flag (default cutoff 24h). Stale accounts are re-verified for real at order time. The badge is also one-shot per account — the moment a 50% order confirms, is_50_eligible flips 1 → 0, because DashPass free trials can only be redeemed once per account.

Scraped promo codes can beat the deal

If /scrape has recorded a promo code worth more than 50% on the account (stored in chain_data.promos_json, account-scope only), the bot picks that scraped code instead of the DashPass deal. Ties go to the 50% deal; a scraped code wins only if its percent is strictly greater than 50.

Async Jobs

Generating accounts and placing orders take time, so they run as background jobs. Those endpoints return 202 with a job_id — poll GET /v1/jobs/{id} until completed or failed. The preview endpoints are synchronous (they return pricing directly). Max 2 active jobs per user. Polling only — no webhooks or callbacks.

Quickstart

1 · Get a key

Run /api_key on Discord and configure /settings.

2 · Generate a batch

POST /v1/gen with a batch_name. Accounts are probed for the 50% deal.

3 · Find eligible

GET /v1/eligible returns the accounts that have the deal, with their account_id.

4 · Preview & confirm

POST /v1/order/preview to see the price, then POST /v1/order/confirm to place it.

Account Snapshot

GET /v1/me Verify key, credits, scopes

Verify your API key and check your credit balance.

Request
curl -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/me
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

r = requests.get(f"{BASE}/v1/me", headers=headers)
r.raise_for_status()
me = r.json()
print("Credits:", me["credits"])
print("Scopes:", me["scopes"])
200 Response
{
  "user_id": 1306300782123159674,
  "credits": 42,
  "scopes": ["gen", "order", "accounts", "otp"],
  "key_prefix": "am_live_8Xk2aB9c..."
}

Generate a Batch

POST /v1/gen Create accounts into a batch + probe 50%

Creates accounts into the named batch and probes each for the 50% deal. SMS key, domain, and List tier come from your Discord /settings. Async — poll the job.

FieldTypeRequiredNotes
batch_namestringYesBatch (chain) to create/append to. Shows in /view on Discord too.
amountintegerNo1–5. Default 1.
account_namestringNoName for the accounts. Random if omitted.
addressstringNoOptional address to attach.
Request
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  -H "Content-Type: application/json" \
  -d '{"batch_name": "june-run", "amount": 2}' \
  https://automunch.site/dd/v1/gen
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

resp = requests.post(f"{BASE}/v1/gen", headers=headers,
                     json={"batch_name": "june-run", "amount": 2})
resp.raise_for_status()
print(resp.json())  # {"job_id": "...", "status": "queued", ...}
202 Response
{
  "job_id": "2f1c...e7",
  "status": "queued",
  "batch_name": "june-run",
  "poll_url": "/v1/jobs/2f1c...e7"
}
Completed Job (poll /v1/jobs)
{
  "status": "completed",
  "result": {
    "batch": "june-run",
    "successful": 2,
    "accounts": [
      {
        "account_id": 8801,
        "email": "johns4d2@outlook.com",
        "password": "Pass123!",
        "first_name": "John", "last_name": "Smith",
        "phone_number": "+11234567890",
        "is_50_eligible": true
      },
      {
        "account_id": 8802,
        "email": "maria9xk@outlook.com",
        "password": "Pass456!",
        "first_name": "Maria", "last_name": "K",
        "phone_number": "+11234500000",
        "is_50_eligible": false
      }
    ]
  }
}

List Batches

GET /v1/batches Your batches + counts

Your batches with totals and how many accounts are still eligible. Mirrors /view on Discord. The auto "Placed Orders" batch (used accounts) is flagged with is_placed_orders. Accounts generated through /v1/order or /order that fail to place land in a dedicated Order Gens batch so they never pollute your clean pools.

Request
curl -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/batches
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

r = requests.get(f"{BASE}/v1/batches", headers=headers)
r.raise_for_status()
for b in r.json()["batches"]:
    print(f'{b["name"]}: {b["total"]} total, {b["eligible_50"]} eligible')
200 Response
{
  "batches": [
    { "id": 12, "name": "june-run", "total": 10,
      "eligible_50": 7, "is_placed_orders": false,
      "created_at": "2026-06-06 04:22:11" },
    { "id": 19, "name": "Placed Orders", "total": 23,
      "eligible_50": 0, "is_placed_orders": true,
      "created_at": "2026-06-05 18:03:44" },
    { "id": 22, "name": "Order Gens", "total": 4,
      "eligible_50": 2, "is_placed_orders": false,
      "created_at": "2026-06-06 11:14:00" }
  ]
}

View a Batch

GET /v1/batches/{name} Accounts in a batch

Accounts in a batch with their eligibility. No raw tokens are returned — has_jwt tells you a usable session exists.

Request
curl -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/batches/june-run
Python
import requests
from urllib.parse import quote

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

name = "june-run"  # may contain spaces / special chars
r = requests.get(f"{BASE}/v1/batches/{quote(name, safe='')}", headers=headers)
r.raise_for_status()
batch = r.json()
for a in batch["accounts"]:
    print(a["account_id"], a["email"], "50:", a["is_50_eligible"])
200 Response
{
  "batch": "june-run", "chain_id": 12, "total": 10,
  "accounts": [
    { "account_id": 8801, "account_number": 1,
      "email": "johns4d2@outlook.com", "phone": "+11234567890",
      "is_50_eligible": true, "checked_at": "2026-06-07 06:40:12",
      "stale": false, "has_jwt": true },
    { "account_id": 8803, "account_number": 3,
      "email": "alex7p@outlook.com", "phone": "",
      "is_50_eligible": null, "checked_at": null,
      "stale": null, "has_jwt": true }
  ]
}

List Chains

GET /v1/chains Your batches by chain id

Lower-level listing of every batch (chain) you own, keyed by numeric chain_id. Use this when you want to look batches up by id rather than by name. Returns the same batches as /v1/batches; the auto Placed Orders, Fraud-Retired, and Order Gens chains show up here with their flags.

Request
curl -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/chains
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

r = requests.get(f"{BASE}/v1/chains", headers=headers)
r.raise_for_status()
for c in r.json()["chains"]:
    print(c["chain_id"], c["name"], c["total"])
200 Response
{
  "chains": [
    { "chain_id": 12, "name": "june-run", "total": 10,
      "eligible_50": 7, "is_placed_orders": false,
      "is_fraud_retired": false, "is_order_gens": false },
    { "chain_id": 19, "name": "Placed Orders", "total": 23,
      "eligible_50": 0, "is_placed_orders": true,
      "is_fraud_retired": false, "is_order_gens": false },
    { "chain_id": 22, "name": "Order Gens", "total": 4,
      "eligible_50": 2, "is_placed_orders": false,
      "is_fraud_retired": false, "is_order_gens": true }
  ]
}

Accounts in a Chain

GET /v1/chains/{chain_id}/accounts Lookup accounts by chain id

Same shape as /v1/batches/{name}, but keyed by numeric chain_id — handy if you cached chain ids from /v1/chains and don't want to deal with URL-encoding a name.

Request
curl -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/chains/12/accounts
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

chain_id = 12
r = requests.get(f"{BASE}/v1/chains/{chain_id}/accounts", headers=headers)
r.raise_for_status()
for a in r.json()["accounts"]:
    print(a["account_id"], a["email"], "50:", a["is_50_eligible"])

Eligible Accounts

GET /v1/eligible Accounts with the 50% deal

Every account that currently has the 50% deal, across all batches. Use the account_id to place an order.

Excludes the auto Placed Orders and Fraud-Retired chains.
Query paramNotes
batchOnly this batch.
fresh_onlytrue drops accounts whose deal is stale (older than the cutoff).
Request
curl -H "Authorization: Bearer am_live_..." \
  "https://automunch.site/dd/v1/eligible?fresh_only=true"
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

r = requests.get(f"{BASE}/v1/eligible", headers=headers,
                 params={"batch": "june-run", "fresh_only": "true"})
r.raise_for_status()
elig = r.json()
print(f'{elig["count"]} fresh eligible accounts')
for a in elig["accounts"]:
    print(a["account_id"], a["email"])
200 Response
{
  "count": 2,
  "stale_cutoff_hours": 24,
  "accounts": [
    { "account_id": 8801, "email": "johns4d2@outlook.com",
      "batch": "june-run", "checked_at": "2026-06-07 06:40:12",
      "stale": false },
    { "account_id": 8815, "email": "kayla2v@outlook.com",
      "batch": "june-run", "checked_at": "2026-06-06 09:12:00",
      "stale": true }
  ]
}

Preview a Checkout

POST /v1/order/preview See the price before placing

Prepares and prices the order without placing it — nothing is charged. It loads the account, resolves the cart + address, and if the 50% deal is on offer it subscribes the free DashPass trial card-free (stripe_id empty — no payment method is attached, so the trial cannot auto-charge if left to expire). Returns the real discounted price plus an order_session_id you confirm later. Synchronous (no job).

FieldRequiredNotes
account_idYes*From /v1/eligible. (*or a raw jwt_token)
jwt_tokenYes*Raw DoorDash JWT — alternative to account_id, bypasses the stored session.
cart_urlYesDoorDash group cart (https://drd.sh/cart/...) or a custom cart from the browser extension (automunch.site/cart/...)
addressYesDelivery address, e.g. "123 Main St, 30301" — set as the account default automatically
cardNoOptional at preview (card is needed at confirm). {number, exp_month, exp_year, cvv, zip}
tip_centsNoTip in cents (e.g. 200 = $2.00)
store_idNoPin the preview to a specific DoorDash store id (skips store resolution from the cart).
subscribe_dashpassNoDefault true. Set false to skip the free-trial subscription step.
wait_for_50_offNoDefault true. If the 50% deal hasn't settled yet, wait a few seconds for it to show before quoting.
scheduled_timeNoISO-8601 scheduled delivery time (requires delivery_option: "SCHEDULE").
promo_codesNoArray of up to 5 promo codes to try. The server auto-rotates — your codes are unioned with every scraped ≥30% code in the dd_promos table, codes already used on this account are filtered out, and the survivors are shuffled. Designed to beat DoorDash's fraud_block_promo_abuse verdict.
+ optionsNoAny order option also prices here: delivery_option, track, address_swap, gift…
Request
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": 8801,
    "cart_url": "https://drd.sh/cart/abc",
    "address": "123 Main St, 30301",
    "tip_cents": 200
  }' \
  https://automunch.site/dd/v1/order/preview
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

r = requests.post(f"{BASE}/v1/order/preview", headers=headers, json={
    "account_id": 8801,
    "cart_url": "https://drd.sh/cart/abc",
    "address": "123 Main St, 30301",
    "tip_cents": 200,
})
r.raise_for_status()
preview = r.json()
print(preview["pricing"]["total"], preview["order_session_id"])
200 Response
{
  "order_session_id": "os_7Fk2aB...",
  "expires_at": "2026-06-07T07:51:00Z",
  "store": { "store_id": "44321", "store_name": "Chipotle" },
  "cart": { "items": [ { "name": "Burrito Bowl", "quantity": 1, "price_cents": 1095 } ],
            "item_count": 1 },
  "dashpass": { "has_50_off": true, "subscribed": true, "already_active": false },
  "pricing": {
    "subtotal": 1095,
    "delivery_fee": 199,
    "service_fee": 65,
    "tax": 47,
    "discount": 985,
    "tip": 200,
    "delivery_option": "STANDARD",
    "express_fee": 0,
    "promotions": [
      { "code": "DASHPASS50", "amount": 985, "type": "dashpass_50" }
    ],
    "is_dashpass_applied": true,
    "total_before_discount": 1606,
    "total_after_discount": 621,
    "total": 621,
    "total_savings": 985,
    "is_prediction": false,
    "note": "Live price — DashPass active, 50% deal applied."
  }
}

Edit a Preview

POST /v1/order/preview/{id}/edit Change something and re-quote

Change any field on an open preview session and get a new quote — just like the edit buttons on the Discord checkout. Send only the fields you want to change.

Editable fields
address, cart_url (swap the group link), tip_cents, promo_codes, gift, is_pickup, dasher_instructions, gate_code, unit, building_name, pin_coords, account_name, account_id, jwt_token, cancel_dashpass_after
Request — change the delivery address
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  -H "Content-Type: application/json" \
  -d '{"address": "55 Oak Ave, 30305", "tip_cents": 500}' \
  https://automunch.site/dd/v1/order/preview/os_7Fk2aB.../edit
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

sid = "os_7Fk2aB..."
r = requests.post(f"{BASE}/v1/order/preview/{sid}/edit", headers=headers, json={
    "address": "55 Oak Ave, 30305",
    "tip_cents": 500,
})
r.raise_for_status()
updated = r.json()
print("New total:", updated["pricing"]["total"])
Returns

The same shape as /v1/order/preview (updated pricing, cart, etc.) for the same order_session_id. Changing cart_url is the heavy edit — it's a new cart, so the deal is re-checked.

Cancel a Preview

POST /v1/order/preview/{sid}/cancel Drop an open preview session

Explicitly cancel an open preview session. Frees the account (so a next preview on the same account doesn't collide), rolls back the DashPass free-trial subscription that was taken for the quote, and marks the session cancelled. Idempotent — calling it on an already-cancelled or expired session returns 200 with already_cancelled: true.

Request
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/order/preview/os_7Fk2aB.../cancel
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

sid = "os_7Fk2aB..."
r = requests.post(f"{BASE}/v1/order/preview/{sid}/cancel", headers=headers)
r.raise_for_status()
print(r.json())  # {"cancelled": true, "dashpass_rolled_back": true}
200 Response
{
  "cancelled": true,
  "already_cancelled": false,
  "dashpass_rolled_back": true,
  "order_session_id": "os_7Fk2aB..."
}

Confirm & Place

POST /v1/order/confirm Place the previewed order

Async, returns 202 + job_id. DashPass handling: before placing we cancel any existing trial, fall back to a card-free subscribe if the card step fails, and retry a post-order cancel on completion to prevent the $9.99 trial charge. Re-verifies the deal is still good, charges the card, fetches tracking, and moves the account to "Placed Orders". You can pass last-second overrides (tip_cents, dasher_instructions, …).

Request
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  -H "Content-Type: application/json" \
  -d '{"order_session_id": "os_7Fk2aB..."}' \
  https://automunch.site/dd/v1/order/confirm
Python — async (202, then poll)
import time, requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

r = requests.post(f"{BASE}/v1/order/confirm", headers=headers,
                  json={"order_session_id": "os_7Fk2aB..."})
r.raise_for_status()
# 202 Accepted — place is now running in the background
job = r.json()
print("Queued:", job["job_id"])

# poll until completed
while True:
    s = requests.get(f'{BASE}/v1/jobs/{job["job_id"]}', headers=headers).json()
    if s["status"] in ("completed", "failed"):
        print(s)
        break
    time.sleep(3)
202 Response
{ "job_id": "9b7a...11", "status": "queued", "poll_url": "/v1/jobs/9b7a...11" }
Completed Job — full order result
{
  "status": "completed",
  "credits_charged": 3,
  "result": {
    "order": { "order_uuid": "a1b2c3d4-...",
               "verified": { "confirmed": true, "status": "scheduled" } },
    "account": { "account_id": 8801, "email": "johns4d2@outlook.com",
                 "consumer_id": "987654321" },
    "store": { "store_id": "44321", "store_name": "Chipotle" },
    "pricing": {
      "subtotal": 1095,
      "delivery_fee": 199,
      "service_fee": 65,
      "tax": 47,
      "discount": 985,
      "tip": 200,
      "delivery_option": "STANDARD",
      "express_fee": 0,
      "promotions": [
        { "code": "DASHPASS50", "amount": 985, "type": "dashpass_50" }
      ],
      "is_dashpass_applied": true,
      "total_before_discount": 1606,
      "total_after_discount": 621,
      "total": 621,
      "total_savings": 985
    },
    "dashpass": { "has_50_off": true, "verified_50_off": true,
                  "cancelled_after": true },
    "gift": { "tracking_url": "https://www.doordash.com/orders/a1b2c3d4-.../gift",
              "doomdash_tracking_url": "https://doomdash.online/track/X7K2" },
    "consume": { "eligibility_used": true, "moved_to_batch": "Placed Orders",
                 "got_50": true },
    "credits_charged": 3
  }
}

One-Shot Order

POST /v1/order Preview + place in one call

Skips the preview step — prepares and places in one async job. Use this when you don't need a confirmation screen. Same body as preview, plus the full order options below; card is required. In mode: "signup" this is also a "gen & order" shortcut — it signs up a brand-new account inline, then orders. If the sign-up succeeds but the order itself fails, the fresh account lands in your Order Gens batch (not Placed Orders) so you can retry it later.

FieldNotes
mode"login" (default) uses an existing account · "signup" creates a new account inline, then orders on it.
cart_url, address, cardRequired (any mode).
Login mode (mode: "login") — identify the existing account
account_idPreferred — looks up the stored session.
jwt_tokenAlternative to account_id: a raw DoorDash JWT.
email / passwordAlternative: log in on the fly (needs device_id).
device_id, dd_session_id, dd_login_idDevice-identity fields for a fresh login (optional with jwt_token).
Signup mode (mode: "signup") — create the account first
sms_api_keyOverrides the SMS key saved in /settings.
signup_domainEmail domain for the new mailbox. Default "outlook.com".
custom_emailFull email to use for sign-up instead of a generated one.
account_nameFirst/last on the new account (random if omitted).
list_sms_service"DDPublic" (default) · "DDPremium" · "Mixed" (auto-pick, uses Premium when the 50% deal shows). Note: an order that uses DDPremium numbers is billed at the 50% rate; DDPublic and Mixed orders are billed at the lower 40% rate — see Credits.
Shared order options
tip_cents, is_pickupStandard order options.
promo_codesUp to 5. Auto-rotated per account — pass a list and the server picks ones unused on that account.
subscribe_dashpassDefault true. Set false to not take the free trial.
wait_for_50_offDefault true. Give the 50% deal a few extra seconds to settle before placing.
cancel_dashpass_afterDefault true — cancels the DashPass trial after every order (success and hard failure) so the free trial never auto-charges. The card-free subscribe already removes the ability to charge, but this still ends the subscription cleanly.
delivery_optionSTANDARD (default) · PRIORITY (express) · SCHEDULE. With SCHEDULE, pass scheduled_time (ISO) or scheduled_min_time / scheduled_max_time. The express_fee is echoed back in pricing.
scheduled_min_time / scheduled_max_timeWindow (ISO) for a scheduled delivery; the engine books the first open slot inside the window.
trackDefault true — places as a gift so the order returns a public tracking link (no login). Set false for a plain order.
address_swapDeliver to a random nearby (~500m) address instead of the exact one — anti-ban. address_swap_radius tunes the distance.
dasher_instructions, gate_code, unit, building_name, pin_coordsDelivery details (pin = "lat,lng")
giftOverride the default self-gift with a custom recipient: {enabled, recipient_name, recipient_phone, card_message}. Shortcut: pass sender_name and card_id at the top level and the engine builds the gift block for you.
sender_nameTop-level shortcut — becomes the "from" on the gift receipt.
card_idTop-level shortcut — DoorDash gift-card art id for the gift receipt.
store_idPin to a specific DoorDash store id (skips store resolution from the cart).
Promo rotation

promo_codes is auto-rotated per account — pass a list and the server picks ones unused on that account. Codes that have already been consumed by this account are filtered out, so the same list can be reused on every call without burning codes.

Request
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": 8801,
    "cart_url": "https://drd.sh/cart/abc",
    "address": "123 Main St, 30301",
    "card": { "number": "4242424242424242", "exp_month": "12",
              "exp_year": "27", "cvv": "123", "zip": "30301" },
    "tip_cents": 200,
    "gift": { "enabled": true, "recipient_name": "Jane",
              "recipient_phone": "+15551234567" }
  }' \
  https://automunch.site/dd/v1/order
Python — mode: "login" (existing account)
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

payload = {
    "mode": "login",
    "account_id": 8801,
    "cart_url": "https://drd.sh/cart/abc",
    "address": "123 Main St, 30301",
    "card": {"number": "4242424242424242", "exp_month": "12",
             "exp_year": "27", "cvv": "123", "zip": "30301"},
    "tip_cents": 200,
    "promo_codes": ["YOUGOT40", "SAVE40", "APP40"],
    "subscribe_dashpass": True,
    "wait_for_50_off": True,
    "cancel_dashpass_after": True,
    "gift": {"enabled": True, "recipient_name": "Jane",
             "recipient_phone": "+15551234567"},
}

r = requests.post(f"{BASE}/v1/order", headers=headers, json=payload)
r.raise_for_status()
job = r.json()
print("Queued:", job["job_id"])
Python — mode: "signup" (gen & order)
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

payload = {
    "mode": "signup",
    "signup_domain": "outlook.com",
    "list_sms_service": "DDPublic",
    "account_name": "Jamie R",
    "cart_url": "https://drd.sh/cart/abc",
    "address": "123 Main St, 30301",
    "card": {"number": "4242424242424242", "exp_month": "12",
             "exp_year": "27", "cvv": "123", "zip": "30301"},
    "tip_cents": 200,
    "sender_name": "Jamie",
    "card_id": "balloons-01",
}

r = requests.post(f"{BASE}/v1/order", headers=headers, json=payload)
r.raise_for_status()
job = r.json()
print("Queued signup+order:", job["job_id"])
# If signup succeeds but ordering fails, the fresh account
# lands in your "Order Gens" batch for a retry.

Returns 202 with a job_id; the completed job has the same full order result as Confirm above.

Check Eligibility

POST /v1/check_50 Probe one account's 50% deal

Probe a single account's 50%-off (50% DashPass) eligibility without ordering. Synchronous.

Request
curl -X POST \
  -H "Authorization: Bearer am_live_..." \
  -H "Content-Type: application/json" \
  -d '{"jwt_token": "eyJhbG..."}' \
  https://automunch.site/dd/v1/check_50
Python
import requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
headers = {"Authorization": f"Bearer {API_KEY}"}

# Probe by account_id (uses the stored session)...
r = requests.post(f"{BASE}/v1/check_50", headers=headers,
                  json={"account_id": 8801})
r.raise_for_status()
print(r.json())  # {"checked": true, "eligible_50": true, ...}

# ...or by raw JWT:
r2 = requests.post(f"{BASE}/v1/check_50", headers=headers,
                   json={"jwt_token": "eyJhbG..."})
r2.raise_for_status()
print(r2.json())
200 Response
{ "checked": true, "eligible_50": true, "savings": "$12.65",
  "subtotal_cents": 2500, "reason": "ok" }

Poll a Job

GET /v1/jobs/{job_id} Status & result of a gen/order job

Poll until completed or failed.

Request
curl -H "Authorization: Bearer am_live_..." \
  https://automunch.site/dd/v1/jobs/9b7a...11
Python — gen → eligible → preview → confirm
import time, requests

API_KEY = "am_live_..."
BASE = "https://automunch.site/dd"
H = {"Authorization": f"Bearer {API_KEY}"}

def wait(job_id):
    while True:
        j = requests.get(f"{BASE}/v1/jobs/{job_id}", headers=H).json()
        if j["status"] in ("completed", "failed"):
            return j
        time.sleep(3)

# 1) generate a batch
job = requests.post(f"{BASE}/v1/gen", headers=H,
                    json={"batch_name": "june-run", "amount": 2}).json()
wait(job["job_id"])

# 2) find an eligible account
elig = requests.get(f"{BASE}/v1/eligible?fresh_only=true", headers=H).json()
acct = elig["accounts"][0]["account_id"]

# 3) preview
prev = requests.post(f"{BASE}/v1/order/preview", headers=H, json={
    "account_id": acct,
    "cart_url": "https://drd.sh/cart/abc",
    "address": "123 Main St, 30301",
    "card": {"number": "4242424242424242", "exp_month": "12",
             "exp_year": "27", "cvv": "123", "zip": "30301"},
}).json()
print("You pay:", prev["pricing"]["total"])

# 4) confirm
conf = requests.post(f"{BASE}/v1/order/confirm", headers=H,
                     json={"order_session_id": prev["order_session_id"]}).json()
result = wait(conf["job_id"])
print(result["result"]["order"]["order_uuid"])

Credits & pricing

A subscription unlocks the API; credits are then spent per checkout, scaled by your tier — Lifetime is free, higher tiers cost less. Failed orders never charge. Full tiers + credit packs are on the pricing page.

TierPer 50% checkoutPer 40% checkoutFree checkouts / day
Lifetime00∞
Tier III00∞
Tier II6 credits4 credits15
Tier I6 credits4 credits5
No subscription9 credits6 credits0

40% and 50% orders are billed at flat separate brackets per tier (not a halving formula). An order using DDPremium SMS numbers bills at the 50% rate; DDPublic or Mixed bills at the 40% rate.

ActionCost
Account gen (/v1/gen)Lifetime & Tier III: free, unlimited · Tier II: 50 free / day, then 1 credit each · Tier I: 10 free / day, then 1 credit each · No-sub: 3 credits/account
Preview, eligibility, batch reads, chains, /v1/meFree
Beta (any server member)1 free 50% checkout + 1 free 40% checkout / day, then non-sub rates · 2 free gens / day, then 3 credits each
Shared wallet

Credits come from the same AutoMunch wallet as Discord. Check balance with /v1/me or /balance, top up with /buy on Discord.

Error Codes

StatusMeaning
202Async job accepted — a background job has been queued. The body carries job_id; poll GET /v1/jobs/{id}.
400Missing/invalid field (e.g. batch_name required, no account_id/jwt_token, or daisysms_api_key not configured when /v1/gen is called before /settings is saved).
401Missing, invalid, or revoked API key.
404Account, batch, chain, job, or preview session not found (or not yours / expired).
409The deal lapsed between preview and confirm — re-preview.
429Too many active jobs (max 2).
500Engine error during a synchronous probe/preview.