| Date | Customer | Contacts | Address | Product | Amount | Status |
|---|
| Date | Customer | Contacts | Address | Product | Amount | Shopify |
|---|
| Date | From | For | Amount | Status |
|---|
| Date | Org name | Type | Contact | Address | Status |
|---|
Days are UTC days, as in the growth table. Every day of the period is a row, a day with nothing is 0. Columns in the order of the table's tabs: Users, Reports, SBP, Helps.
Reports API: STATS_API_TOKENS is not set in this admin, so the partners' transfers aren't counted.
| Time | User | Action | Target | Reason | IP | Details |
|---|
| Username | Role | Status | Created |
|---|
How to use this admin panel
Every order paid through Stripe lands here. Once a day, the system (a Lambda function) automatically picks orders up from here and creates them in Shopify. This panel is for seeing what's happening, fixing an address before an order ships, cancelling an order that shouldn't go out, and checking who paid and how much.
Two senders, same rules (once a day at 09:00 UTC, orders older than a day). Orders paid through a Stripe Payment Link are sent by the Lambda. Orders from the site's new checkout (the product cell says "new checkout") are sent by the internal sender built into this panel — the strip above the Queue shows when it runs next and how its last run went. The internal sender also checks Stripe right before sending: if the payment was refunded or disputed, the order is put on hold for a person to decide instead of being sent.
Staging only (the test copy of this panel, never the live one): super-admins also get buttons in that strip — Run intake now, Send ready orders now and Send all now (ignore the 1-day delay) to run the internal sender by hand, and — where Cancel & refund is switched on — test orders for Cancel & refund (Not in Shopify, In Shopify (unfulfilled), In Shopify (fulfilled)). A test order is a Stripe test payment plus, optionally, a Shopify order tagged TEST; Delete test order removes it when you're done.
Every change asks why
Every button that changes a customer's data asks for a reason: a link to the support thread or a short note. That covers editing an order's address; cancelling, reverting or deleting an order record; Unlink, Cancel transfer, Cancel subscription, Resend link and Merge in Customer Search; approving or dismissing an application; editing an organization; and the record actions (change owner, organization, premium, delete account). Nothing is changed without a reason.
The reason goes to the Audit log (its own column) and onto
the changed record itself. The record keeps the value it had before
its first change in <field>_bkp (a later
change never overwrites it) and the latest reason in
<field>_upd_comment, as the team does by hand.
Every change in full is kept in the database next to it (the
upd_history collection), so a developer can undo any of
them. Deleting an account is the one exception: the person's own
data is not kept in the records, the backups or the change history
(the site's own logs and this panel's audit log of earlier actions
are not rewritten).
Queue tab
Orders that have not been sent to Shopify yet.
- Edit address — fix the shipping address, name, email, or phone. This is a real edit: this exact data is what gets sent to Shopify once the order ships.
- Under each status: sends <date> · via Lambda or via internal sender — when the order goes to Shopify and which sender takes it.
- Cancel shipment — cancel the order. It will not be sent to Shopify. The order isn't deleted — it moves to the Sent tab marked "Cancelled", so the history is always visible and the order can be brought back if needed. Right after cancelling, the Cancel & refund window opens: choose a full refund, a partial refund or no refund of the customer's payment.
Order status in the queue:
| Status | What it means |
|---|---|
| Waiting | The order is fresh (created less than a day ago) — the system isn't touching it yet, that's normal, it's just too early. |
| Ready to send | A day has passed, the order is waiting for the next automatic run — it will be sent on its own, nothing to do here. |
| Sending… | New checkout only: the internal sender is creating this order in Shopify right now. Editing and cancelling are blocked for that minute. |
| Outcome unknown | New checkout only: Shopify didn't answer clearly (timeout, server error), so the order may already exist in Shopify. It is never re-sent blindly. Clear error & retry first looks the order up in Shopify: found — it's marked as sent; not found — it goes back to the queue. |
| Refunded — on hold Disputed — on hold | New checkout only: the payment was refunded (or disputed) in Stripe before the order shipped. Cancel the shipment, or Clear error & retry to send it anyway. |
| Error | Click the badge to see why it failed in plain language, jump straight to Edit address with the likely problem fields highlighted, and clear the error once it's fixed. Clearing it doesn't send anything itself — the Lambda already retries automatically on its next run regardless, this just resets what the badge shows. |
Sent tab
Orders that have already been processed — either genuinely sent to Shopify, or cancelled by hand.
- The Shopify column — if the order was actually created in Shopify, you'll see a link like
#12345678. Click it to open the order in Shopify in a new tab — that's how you "go to Shopify". - If it says Cancelled instead of a link — the order was cancelled in this panel (the Cancel shipment button on the Queue tab), it was never created in Shopify at all.
- If it's just a dash "—" — the order is marked processed but has no saved Shopify link (usually older records, from before that was saved).
- via internal sender under the link — the order was sent by the panel's own sender (new checkout), not the Lambda.
- TEST — deleted (staging only) — a test order: it was really created in Shopify with the TEST tag and deleted right away, so there's no link. TEST still in Shopify! means deleting it failed — delete it in Shopify by hand.
- For genuinely sent orders — Delete record: hides the record in this panel, to keep the list tidy. It stays in the database with its reason, and the actual order in Shopify is not touched. (A new-checkout record could never be erased anyway — the internal sender would find the payment in Stripe again and send it a second time.)
- For cancelled orders — Revert: puts the order back in the queue, as if it had never been cancelled. The system will pick it up and send it next time around. Not available once the payment was refunded or the order was cancelled in Shopify — the tag would ship for free.
Cancel & refund
Cancelling an order and giving the money back is one flow here, so the refund can't be forgotten. Open it with Cancel shipment (Queue) or Cancel / refund (Sent). The window re-reads the payment in Stripe and the order in Shopify every time and shows the next step:
- Not in Shopify yet — the order is already cancelled in the queue; only the refund is left.
- In Shopify, not fulfilled — Cancel in Shopify cancels it there; the customer gets Shopify's cancellation email. Cancelling in Shopify does not return money — the payment went through Stripe, so refund it below.
- At Flexport — cancelling in Shopify alone does not stop Flexport. Ask Flexport to cancel sends Flexport a cancellation request; Flexport answers later — press Refresh, and once it accepts, cancel the order in Shopify. If the panel can't see the Flexport status, cancel it in Flexport by hand.
- Already fulfilled — it has shipped; Shopify is not touched, only a refund is possible.
Refund: full (whatever is left of the payment), partial (an amount in dollars, never more than is left) or no refund. A reason is always required. A double click never makes two refunds. Every step, including errors, is in the Audit log and on the record itself; each refund is also posted to Slack. A failed refund shows as Refund failed — the cancellation itself stays.
Subscription: if the purchase started a monthly or annual subscription, the window shows it and its status. A refund on its own does not stop it, so a full refund cancels the subscription right away — no more charges, and the site moves the pet back to its previous plan. For a partial refund, tick Cancel the subscription too (off by default); a partial refund of everything that is left counts as full. If the refund went through but the subscription was not cancelled, the window says so and Cancel subscription now tries again. A full refund made in Stripe Dashboard cancels the subscription too — the site does it.
Badges on an order after a cancellation or refund (Sent tab, and Payments for super-admins):
| Badge | What it means |
|---|---|
| Refunded $X | This much of the payment was returned to the customer through Stripe. Hover over it for each refund: amount, who made it, when and why. |
| Refund in progress | A refund was just requested and Stripe hasn't confirmed it yet — wait a moment and reload. |
| Refund outcome unknown | Stripe didn't answer whether the refund went through. A super-admin opens Cancel / refund — the window checks Stripe and settles it. It never refunds twice. |
| Refund failed | Stripe refused the refund; no money moved. The cancellation itself stays. |
| No refund | A super-admin cancelled the order and deliberately chose not to refund (the reason is in the tooltip). |
| Cancelled in Shopify | The order was cancelled in Shopify too (the customer got Shopify's cancellation email). |
| Flexport: cancel requested | Flexport was asked to stop the shipment and hasn't confirmed yet. |
| Shopify cancel failed | Cancelling the order in Shopify didn't work (the reason is in the tooltip) — the order is still live in Shopify. A super-admin opens Cancel / refund and tries again, or cancels it in Shopify by hand. |
| Subscription cancelled | The subscription this purchase started was cancelled after the refund — it no longer charges. |
| Subscription NOT cancelled | The refund went through, but cancelling the subscription failed (the reason is in the tooltip) — it keeps charging. A super-admin opens Cancel / refund and presses Cancel subscription now. |
Payments tab
Super-admin only — a plain admin doesn't see this tab. The full list of every payment — who paid, for what, and how much, regardless of status. There's nothing to do here — it's a ledger for checking and searching. The statuses are the same ones used elsewhere: Paid & sent In queue Send failed Cancelled — and for new-checkout orders also Sending… Outcome unknown On hold (the same as in the Queue: being created in Shopify right now; Shopify's answer was unclear; refunded or disputed in Stripe before shipping). Refund badges from the table above show under the status.
Search boxes (Queue / Sent, and Payments for super-admins)
These tabs all have a search box up top — it searches by customer name, email, or phone within that tab's own list.
Customer Search tab
A different kind of search: this one looks up a person or pet across all of findpet — not just Stripe orders. Use it to answer "who is this microchip/tag/email/phone registered to, what pets do they have, and were any pets transferred?"
- Five separate search boxes at the top: Tag, Microchip ID, Email, Phone, Name. Fill in the one you have and press its own Search button (or Enter).
- Results are grouped the same way every time: owner → their pets → each pet's transfers, shown as cards.
- Email and Phone also look at a pet's extra contacts — the card shows them as Other contacts, so you can see why the pet was found.
- A pet with no matched owner still shows up, under "Pets without a matched owner" — that happens when the owner account was deleted or the pet was never linked to one.
- A transfer with no matched pet shows up under "Transfers without a matched pet" — the contact info matched, but we couldn't tie it back to a specific pet record.
- Addresses link out to Google Maps; pet names and organization names link to their page on findpet.com.
- Super-admins see a confirmation link on a transfer that is still open — the page where the new owner accepts the pet, the same one they got by email/SMS. Handle it like a key: whoever opens it while logged in on findpet.com and presses accept gets the pet. Never press accept yourself; give it only to the new owner (or use Resend link…, which goes to their email/phone). Finished or replaced transfers have no link.
Every search you run here is logged (who searched, which field, what value) — this is sensitive customer data, so don't go searching around out of curiosity. There's also a soft daily limit per person; going over it doesn't block you, it just quietly flags it for review.
Resend link… on an open transfer (everyone can use it) sends the new owner the transfer email again — the very same email, with the same link to accept the pet — and, if you choose Email + SMS, the text message too. The window shows what was sent and where; the SMS option only appears if an SMS was really sent the first time. If there's no email to resend (the address failed validation) but the SMS went out, you get SMS only instead. Nothing is sent from the panel itself: the message goes back into the queue and the regular sender delivers it within a few minutes. It's a real email/SMS to a real person, and it's logged — only use it when the person asked for it.
Possible duplicates (everyone can merge). When you search by email, two records that look like one pet entered twice — typically the shop registered the microchip and the owner then registered the pet again with a tag and photos — are shown side by side at the top, with why they look alike. Merge… opens a window of two steps:
- Which record stays (the main record) is decided for you and the window says why: a shop's or shelter's record first, then the one with the microchip, the paid plan, the tag, photos; otherwise the older one.
- Step 1 lists the fields where the two differ: what the main record has now, what the duplicate has, and which one stays. By default the main record keeps what it has and takes what it's missing; for photos you can also keep Both. The duplicate's tag, microchip and paid plan move to the main record — scanning the tag then opens it.
- Step 2 shows the main record as it will be after the merge (values from the duplicate highlighted) and what moves. Nothing is changed until you press Merge there; Back lets you change your choices.
- After the merge the duplicate is deactivated, not deleted: the owner no longer sees it on findpet.com or in the app, and it disappears from this search. The main record's card shows Merged in with its name and date. There's no undo button — if a merge was wrong, tell the developers (everything is kept and logged).
- The window refuses a merge it can't do safely and says why: two different microchips or tags (unlink the wrong one first), an active subscription on both pets, a pet in a transfer, records of two different organizations, records of two different people (no shared account, email or phone) or of two different owner accounts (one of them would lose the pet). A search by an email or phone only the duplicate had still finds the pet — its main record. If someone changed either record while the window was open, it reloads instead of merging.
Super-admins only also see a few action buttons on the result cards — these change real customer data, so think before clicking:
- Unlink next to a Tag or Microchip — detaches it from that pet. The tag/chip becomes free to link to a different pet.
- Cancel transfer — cancels an in-progress ownership transfer and restores the pet's original owner info. Shown only on the pet's current, still-open transfer: an older transfer that was already accepted, cancelled or replaced (for example by the shop through the partner API, or from the site's dashboard) shows neither Cancel transfer, Resend link nor a confirmation link.
- Cancel subscription — shown on a pet's card only when it has a real recurring Stripe subscription (monthly/annual — a lifetime tariff is a one-time payment with nothing to cancel). Pick at period end (the usual choice — the customer keeps access until what they already paid for runs out, then it lapses on its own) or immediately (access ends right now). Either way this calls Stripe for real; the subscription's own webhook is what updates the pet's tariff back to free once it actually ends. The reason also goes to Stripe, as the cancellation comment.
Record actions — buttons at the bottom of a card, for super-admins. They do what support used to do by hand in the database. Each opens a window that first shows what changes (Now → After) and what stops it; only Confirm, with a reason, changes anything. If the records change while the window is open, it checks again instead of writing.
- Change owner… (pet) — gives the pet to another findpet account, found by its email, without a transfer and without any email to anyone. The pet gets the new owner's name, email and phone (and their address, if you tick it); the old owner's extra contacts are removed. The tag, microchip and paid plan stay with the pet. A paid subscription stays on the old owner's card — the window warns you. Not possible while the pet is in a transfer, for an organization's pet without an owner, or when several accounts have that email (merge them first).
- Return to organization… (pet that came from an organization) — the pet stops being its owner's and goes back to that organization, with the organization's record type (a shelter's pets are Adopt, a shop's are "in shop"…). Tick the box to put the organization's contacts and address on it.
- Change organization… (pet) — moves the pet to another organization by its org_id. An organization's own pet also gets the new organization's record type, so it shows on its dashboard; a pet that belongs to a person only changes where it came from. Past invoices don't change. Not possible for a shop deactivated for unpaid invoices (either side), for a pet in a transfer, or for a record kept in sync with PetPoint (change it there).
- Remove premium… (pet, or owner — then tick their pets) — takes the paid plan off the way the site does when a plan ends: back to the backup tariff (free, or SMS alerts if that was the backup). Not possible while a Stripe subscription is active — cancel it first, or Stripe keeps charging. A monthly or annual plan bought through a Payment Link may still renew in Stripe: the window warns you to check Stripe by hand.
- Delete account… (owner) — deletes the account at the person's request, the same way the app does: name, email, phone, address, password and sign-in links are removed, they are signed out everywhere, their own pets disappear from the site and the app (without contacts, address or tags), their contacts are also cleared from the backups of pets that were theirs before, their organization's pets stay. Type the account's email to confirm. It cannot be undone. Not possible with an active Stripe subscription or a pet in a transfer.
Org approvals tab
Review queue for the two public application forms on findpet.com (Apply for Findpet Organization ID and Apply to Join Findpet's Free Microchip Program for Nonprofits). Two sub-tabs, one per form — each lists submissions newest first, with a status: New (waiting for a decision) or Approved. Dismissed applications disappear from the list.
- New rows have Verify organization and Dismiss (see below).
- Approved rows show the organization's
org_idwith an Edit organization button (opens it in the Organizations tab), and View — a read-only look at the application: its status, who approved it and when, the organization it was linked to, and everything the applicant submitted on the form.
Click Verify organization on a row to:
- Search
organizationsfor a possible existing match — by name, address, and contact email. - If matches are found, pick one (or "none of these — create
new"). For a picked match you choose whether to keep its current
data or overwrite with the form's data as the starting point, and
— if it already has pets on file — whether to hide them (sets
their report status to
inactive) or leave them as is. A link to the organization's existing pets is shown either way. - Either way, a field-by-field form opens (organization name, type, address, public/primary contact, website, logo, social links) pre-filled per the choice above. Where the two sources (database vs. form) disagree, the other value is shown under the field with an Apply button to pull it in instead — edit freely before saving regardless.
- Confirm & save writes the organization (creating or
updating it), applies the pets choice if any, and marks the
application
approved. A newly created organization gets an 8-characterorg_id. It starts with the two-letter state code read from the address — a best guess, e.g.FL7K2M9Q; if no US state code is found, all 8 characters are random. The random characters never use 0/O or 1/I (the state code itself can, e.g.OH…). Dismiss application marks itdismissedwithout touchingorganizationsat all — for spam or duplicates.
Super-admin only — along with Organizations and the Audit log below, this tab isn't shown to a plain admin at all (their menu is Queue/Sent/Customer Search/Help). Every verify/dismiss/view is in the audit log with a before/after snapshot of the organization fields touched where there's something to compare.
Organizations tab
Super-admin only. Look up any organization directly by its
org_id — the search matches a substring
case-insensitively and shows up to 20 results, so a full id finds
the one organization, and a short piece like a state code ("FL")
lists the first 20 ids that contain it anywhere — not strictly
that state's organizations, and not all of them.
Click Edit on a result to fix its profile (name, type,
address, public/primary contact, website, logo, social links)
independent of the application-review flow above — for correcting
a typo or an outdated contact on an organization that isn't tied to
any pending application. Every search and every save is in the
audit log.
The Org approvals list also has a quick Edit organization
link next to an approved application's org_id — it
jumps here and opens the edit form for that organization directly.
Stats tab
Super-admin only. The numbers of the weekly growth table (Findpet growth table, tabs Users, Reports, SBP, Helps) for every day of a period. It opens on the last full week, Monday to Sunday; Last week brings it back, or pick From / To and press Show (up to a year at a time). Download CSV saves what's on screen: one line per day, the columns in the order of the table's tabs, so they can be pasted there as they are. A day with nothing is 0 — no need to fill gaps by hand.
- Days are UTC days, as the table always had them.
- Users — new accounts on the site (Web) and in the app (Apps). Reports — new pet reports, without searches (SBP) and in-shop pets. SBP — new searches by photo. Helps — Similar / Dissimilar votes. Staff and test accounts are left out, as in the old script.
- Reports API — pet transfers of our API partners that
came through the API. The same partners' transfers made from their
dashboard on the site are the last column, Partner transfers
from the site: the old query counted both, so API + that column
is its number. Which partners — the admin's
STATS_API_TOKENS; without it these two columns show —.
Every Show is in the audit log (a download is the numbers already on screen, not a new count).
Audit log tab
Super-admin only. Who logged in and when (and failed or locked-out logins), every address edit, every cancel/revert/delete/retry, every step of a Cancel & refund, every Customer Search (who searched for what) and every action on a result card — Unlink, Cancel transfer, Resend link (opening the window and every attempt, refused ones too), Merge (opening the window, both records as they were before, the outcome), Cancel subscription — every Org approvals/Organizations view, search, approval, dismissal and edit, every record action (Change owner, Return to / Change organization, Remove premium, Delete account — opening the window, the change, refusals), every user created/disabled/enabled or given a new password, and what the internal sender did with each new-checkout order (sent, held, failed, outcome unknown), every Stats period shown — the full history of actions taken in this panel, by every admin (not just your own). Worth checking whenever something looks off and you need to know who did what. The Reason column shows why a change was made — every change asks for one.
Users tab — super-admin only
Add new staff accounts, disable access, reset passwords.