The three arrangements
No agent
The athlete was not represented when they applied. MOGL pays the athlete, and no agent is involved in the deal at all.
Represented, agent paid
MOGL pays the agent through Stripe Express, after retaining the agent commission. The agent settles with the athlete outside MOGL.
Represented, athlete paid
The Notre Dame arrangement. MOGL pays the athlete. The athlete settles with the agent outside MOGL.
Compensation flags on deal and payment responses
Four fields were added to the responses the clients already call. No new request parameters, no version bump — existing calls simply return more fields.Where the flags appear
Fan requests and referral payments always return
is_agent_represented: false, payout_recipient: "Athlete", agent_gets_paid: false, agent_name: null. The shape is identical across every row so the clients do not need a special case.Which amount to show the athlete
Athlete Pay screens show what the athlete earned on the deliverable, never the transfer that was made to the agent.
On
paymentHistoryAthlete the two are equal whenever the athlete was paid directly, so the difference only shows up on deals paid to an agent: there amount_paid is the agent’s net after commission. gross_amount was added for this reason and is the one to bind to.
What to show
For the badge in list and detail views,is_agent_represented is the one that answers “is an agent involved in this deal”, and agent_name names them. For anything about money, use agent_gets_paid.
The two combine into three states. What gets said about each one depends on the surface, which the next section sets out.
Approved athlete-facing copy
My Deals and Pay answer different questions, so they use different flags. Getting this backwards is the most likely mistake here.
An athlete-direct payment uses the ordinary Pay row: no badge, and no mention of the agent, even though the athlete was represented. The representation is communicated on My Deals, not on Pay.
Copy, with
{AgentName} from agent_name:
The Pay string names the deliverable’s gross amount rather than saying a payment of that amount was made, because the agent received the net. Do not word it as though the gross was transferred.
Athlete-facing amounts
Athlete surfaces show the gross deal compensation only. The MOGL deduction and the net that went to the agent stay on the agent side. Do not compute what the athlete’s own share of an agent payment was; MOGL does not know what the agent later paid them.Total Pay to Date caption
athletePaymentTotal returns a new includes_agent_payments boolean, at the top level and inside data alongside total.
total is gross compensation for completed payments, which already includes deals the agent was paid for. That is what makes the caption necessary: the number alone cannot say that some of the money went somewhere else.
Do not try to work this out from the payment history list. That list is paginated, so an agent-directed row may not be on the page you have. The flag is computed over exactly the payments the total summed, from the payout records, so it stays correct after a representation ends.
Agent Pay view
amount_to_agent: 0. They are in the feed on purpose: leaving them out told an agent that a deal they handled did not exist.
Authorization: requires an authenticated Agent (role_id 4). A caller with any other role receives 403. There is no way to request another agent’s feed.
Query parameters
These are the same parameter names the athlete Pay endpoints accept, so one filter bar drives both views.
Rows come back newest first, with a deterministic tie-breaker. Pagination, filtering, and ordering all happen server-side.
Response
Standard Laravel resource collection withdata, links, and meta.
Reading the money fields
This is the part most likely to be displayed wrongly, so it is worth being precise.
The agent’s commission is the only thing taken out of the gross, so
commission_amount and agent_commission_amount agree and commission_percentage applied to gross_amount produces both.
Athlete-direct rows
On a row wherepayout_recipient is "Athlete", MOGL paid the athlete and kept nothing from the agent. Those rows carry:
gross_amount— the deal value, the same figure an agent-paid row leads withamount_to_agent—0commission_amount,agent_commission_amount,commission_percentage,net_amount— allnull, because there was no agent payout to take a commission from
In-flight rows
A row appears once the deliverable’s payment has been requested or made. Work that is still in progress belongs to My Deals, not here. On those rowsgross_amount is the deliverable price and commission_percentage, agent_commission_amount, and net_amount are all null. So is amount_to_agent, when the agent is the recipient; an athlete-direct row reports 0 whether or not it has been paid, because the agent’s share is already known to be nothing. This is deliberate: a figure calculated from the agent’s current commission rate would read as a promise, and the rate that finally applies is whatever ends up stored on the payout. Show these as pending rather than as zero.
payout_id and transaction_id are also null until they exist.
Null and zero mean different things here. Null is “not settled yet”; zero is “settled, and none of it was the agent’s”.
Status values
These are the three the athlete Pay screens use, and the feed carries no others. A deliverable’s own lifecycle — assigned, submitted, approved — is My Deals’ subject, and repeating it here made Pay read as a second deal list.
A failed payout reads
Processing rather than disappearing or reading Failed: the money is still owed, and Pay has never had a failure state. Back Office is where a failed attempt is diagnosed.
Status describes the deal’s payout, not the agent’s share specifically. An athlete-direct row reads Paid once the athlete was paid, alongside amount_to_agent: 0.
A deliverable a brand settled outside MOGL is recorded rather than transferred, and it reads Paid with payment_mode: "Paid Manually". On an agent-recipient deal the amount now shows as money to the agent, because the party the deal owed is the party the record names. Deals settled this way before this release name the athlete regardless, so they appear as athlete-direct; nothing observed who actually received that money, so it was not rewritten.
What is not in this feed
No deals the agent never represented
Membership comes from what the application recorded, not from the agent’s current roster. An agent taking on an athlete does not inherit deals from before.
No subscriptions or card charges
Agent subscriptions are deprecated. There are no charges against an agent card, no billing-card last four, and no subscription rows.
History survives unlinking
Rows are keyed to the representation the application recorded and to the payout that reached the agent, neither of which is deleted when an athlete is unlinked. An agent keeps seeing every deal they handled and what they were paid for it.Deals from before this feature
Applications made before representation was recorded were given it once, by a one-off migration, under rules that differ from the rules for new applications. Nothing about the response shape changes; only which old deals appear.
The middle row is the one to expect questions about: a completed old deal that an agent submitted but the athlete was paid for is not in that agent’s Pay view, because a finished payment is treated as the record of who was involved. Athlete-direct deals created after this release do carry representation and do appear, reading
amount_to_agent: 0. The difference is confined to deals that were already paid before the migration ran.
Empty and error states
Athlete notification
When a payout goes to an agent, the athlete’s notification now says the money was sent to the named agent rather than that a payment is on its way to them. Clients do not need to change anything for this; it is server-side copy.Email, push and SMS branch on the recipient server-side. The template rows for the agent variants are a content task, tracked separately from the client work.
Client checklist
1
Show agent involvement from is_agent_represented
Athlete My Deals and Pay, agent My Deals, iOS My Deals and Deal Details. Name them from
agent_name.2
Show anything about money from agent_gets_paid
Never from
is_agent_represented, and never from who applied, and never from the current agent link.3
Point the agent Pay route at /api/agent/pay-feed
Remove the athlete selector and any
selectedAthlete dependency.4
Render gross, retained, and net from the stored fields
Lead with
gross_amount and amount_to_agent, and show commission_amount as the retained commission. Treat null amounts as pending and 0 as settled at nothing.5
Keep failed payouts visible
They are part of the feed.
Swagger:
GET /agent/pay-feed is documented in Core API (Agent - Pay).