Sync Wingspan to Oracle Fusion Cloud ERP
Post Wingspan payables, payments, invoices, and contractor onboarding to Oracle Fusion Cloud ERP. A pattern guide covering object mapping, the event-driven sync, and the Fusion REST details that trip up a first build.
You write the middleware that reads activity from Wingspan and writes it to Oracle Fusion Cloud. The sync only reads from Wingspan. It records in Fusion what already happened in Wingspan, and it never moves money.
Where Wingspan fits
- Wingspan onboards your contractors, collects card and ACH payments from your clients, records checks and wires paid outside Wingspan, pays contractors, and files 1099s.
- Oracle Fusion Cloud is the general ledger: Payables (AP) for what you owe contractors, Receivables (AR) for what your clients owe you, and the chart of accounts behind both.
Data flows one way, from Wingspan to Fusion. Fusion stays the book of record, and Wingspan stays the record of every payment. Wingspan already paid the contractor or collected from the client; Fusion records what happened.
How the sync works
Wingspan pushes Payable.Paid, Invoice.Opened, and InvoicePayment.Completed events to your webhook as they happen. Every 15 minutes your sync also reads the 30-day event log from a saved cursor, which catches anything a push missed. Run a parallel sweep of GET /v3/search/payable-rows?filter[status][eq]=Paid and GET /v3/search/invoice-rows by status on the same schedule, to catch anything the event system missed entirely.
Treat every event as a pointer. Read the payable or invoice from Wingspan, convert it, and write to Fusion only what Fusion doesn't already have. Each pass converges Fusion to Wingspan's current state, so duplicate, late, and out-of-order deliveries all end in the same place.
Keep a sync log that maps each Wingspan ID to the Fusion invoice number (AP and AR) and payment number it became. It's your first stop before any Fusion write, and it's what a person reads when something fails.
Run all work for one Wingspan object on one worker at a time, with a lock keyed on the Wingspan ID. A webhook and the status sweep can arrive for the same payable at once, and without the lock both pass the lookup and both write.
sequenceDiagram
participant WS as Wingspan
participant Sync as Your sync
participant F as Fusion Cloud
WS->>Sync: Webhook (Payable.Paid)
Sync->>Sync: Lock the payable ID
Sync->>WS: GET /v3/payments/payables/{id}?expand=payee
Sync->>Sync: Sync log: does a Fusion invoice exist for this payable?
Sync->>F: GET /fscmRestApi/resources/.../invoices?q=InvoiceNumber=<id>
Sync->>F: POST invoices (on a miss), then action/validateInvoice
Sync->>F: POST payablesPayments, type Manual, linking the invoice
Sync->>Sync: Record the Fusion invoice number and payment number, mark the event processed
Note over Sync,WS: Every 15 minutes: event log from the cursor, then a status sweep
Set up Fusion Cloud first
Do this with your Oracle admin before the first sync.
- Auth. Either a named Fusion service user authenticated with HTTP Basic over TLS, or an OAuth2 client-credentials client registered through the Security Console. Client-credentials still runs as a named user under the hood; whichever you pick, that user needs the job roles below.
- Job roles and data access. The integration user needs Accounts Payable Specialist, Supplier Administrator or Supplier Manager, Billing Specialist, and Integration Specialist (for the
erpintegrationsresource used for bulk loads), plus data access assigned for every Business Unit the sync touches. A missing Business Unit assignment returns a403or a silently empty result set, not a clear error. - A chart-of-accounts mapping. Your controller maps Wingspan's own dimensions (client, contractor group, cost center, whatever you track) to Fusion's existing GL account combination. The chart of accounts is already configured; nothing new to build there.
- A Descriptive Flexfield for the Wingspan reference. Fusion's invoices and suppliers don't have a typed "external ID" field the way some systems do. Ask your Oracle admin for a Descriptive Flexfield on the AP invoice header (or use the invoice number itself, see below) and on the AR invoice, so a person in Fusion can trace a record back to Wingspan.
- A disbursement setup for AP payments. Before you can record a single payment, your Oracle admin needs: a dedicated clearing bank account for "paid by Wingspan," a payment method and payment process profile configured for manual, external payments, and a numbered payment document against that bank account. The
payablesPaymentscall below fails without all four. - A pay group or payment method exclusion. Once an AP invoice is validated and approved, it's eligible for the client's normal Payment Process Request unless something excludes it. Agree with your controller on a dedicated pay group or payment method that your invoices use, which the standard PPR selection criteria skip. Without this, Fusion can select and pay the invoice itself before your sync records Wingspan's own payment, and the contractor gets paid twice.
- Suppliers marked Spend Authorized. A new supplier defaults to
BusinessRelationship: Prospective. Payables rejects an invoice against a Prospective supplier, so the onboarding step below sets it toSpend Authorizedexplicitly. - 1099 ownership. If Wingspan files the contractor's 1099, set
FederalReportableFlagtofalseon every supplier the sync creates, so Fusion's own 1099 process doesn't also file for them.
Map your objects
| Wingspan | Fusion Cloud | Notes |
|---|---|---|
| Payee | Supplier (POST /fscmRestApi/resources/.../suppliers) | TaxOrganizationType: Individual for a 1099 contractor, BusinessRelationship: Spend Authorized. |
| Payee's payout bank account | External Bank Account + External Payee | Separate resources from suppliers; a single BATCH call can't span Procurement and Financials resource families, so this is at least two calls. |
Payable, once Paid | Payables invoice (invoices), then a payablesPayments record | The invoice is created and immediately paid, since the webhook that triggers this sync is Payable.Paid. |
| Payable line item | invoiceLines[] | LineAmount, DistributionCombination carrying the mapped GL account. |
| Payer | Customer (hubOrganizations for the party, then an AR customer account) | See Receivables for the account/site step. |
Invoice, once Opened | Receivables invoice (receivablesInvoices) | TransactionSource must be a manual-type source configured in Receivables. |
| Invoice line item | receivablesInvoiceLines[] | accounting-style dimensions carried as needed by your mapping. |
Invoice payment, Completed | standardReceipts, applied via a remittanceReferences child | Oracle's own async AutoMatch process applies it; there's no synchronous REST apply. |
Onboarding: create the supplier
On Payee.Activated, or as soon as you have what you need, create the Fusion supplier:
curl -X POST "https://your-pod.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/suppliers" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"Supplier": "Priya Shah",
"TaxOrganizationType": "Individual",
"TaxpayerCountry": "US",
"TaxpayerId": "123-45-6789",
"BusinessRelationship": "Spend Authorized",
"FederalReportableFlag": false
}'TaxpayerId is the attribute name, not TaxpayerIdentificationNumber. Leave SupplierNumber unset unless the client uses manual numbering; Fusion auto-assigns it. Then create at least one site before you can invoice this supplier:
curl -X POST ".../suppliers/{supplierId}/child/sites" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{ "SupplierSite": "MAIN", "ProcurementBU": "<your BU>", "AddressLine1": "...", "City": "...", "Country": "US" }'Bank account setup is a separate pair of calls against External Bank Accounts and External Payees, and whether you need it at all depends on the payment direction you chose during scoping: if Wingspan disburses and Fusion only mirrors the payment (the pattern this guide follows), the contractor's bank details don't need to exist in Fusion at all.
Payables
On Payable.Paid:
1. Find or create the invoice
curl -g ".../invoices?q=InvoiceSource=Wingspan;InvoiceNumber=<payableId>" \
-u "$FUSION_USER:$FUSION_PASSWORD"On a miss, create it with lines nested inline:
curl -X POST ".../invoices" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"BusinessUnit": "US Business Unit",
"InvoiceNumber": "WS-PAY-4471",
"InvoiceCurrency": "USD",
"InvoiceAmount": 1200.00,
"InvoiceDate": "2026-10-09",
"InvoiceType": "Standard",
"Supplier": "Priya Shah",
"SupplierSite": "MAIN",
"InvoiceSource": "Wingspan",
"invoiceLines": [
{ "LineNumber": 1, "LineType": "Item", "LineAmount": 1200.00, "DistributionCombination": "01-000-5100-0000-000" }
]
}'InvoiceSource must match a configured Payables source lookup (Wingspan here), or omit it to default to External. The line amount field is LineAmount, not Amount.
2. Validate it
curl -X POST ".../invoices/action/validateInvoice" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{ "ProcessAction": "Validate", "BusinessUnit": "US Business Unit", "Supplier": "Priya Shah", "InvoiceNumber": "WS-PAY-4471" }'An invoice must be validated before Fusion will let you record a payment or post accounting.
3. Record Wingspan's payment
curl -X POST ".../payablesPayments" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"PaymentNumber": "WS-PAY-4471-01",
"PaymentType": "Manual",
"PaymentDate": "2026-10-09",
"PaymentCurrency": "USD",
"BusinessUnit": "US Business Unit",
"Payee": "Priya Shah",
"PayeeSite": "MAIN",
"DisbursementBankAccountName": "Wingspan Clearing Account",
"PaymentMethod": "Manual",
"PaymentProcessProfile": "Wingspan Manual Payments",
"PaymentDocument": "Wingspan Clearing Checks",
"relatedInvoices": [
{ "InvoiceNumber": "WS-PAY-4471", "InstallmentNumber": 1, "AmountPaidPaymentCurrency": 1200.00 }
]
}'PaymentNumber is required. InstallmentNumber is required on every relatedInvoices item, not just the invoice number. PaymentAmount isn't sent; Fusion computes it from relatedInvoices.
This call fails if the installment is on hold, needs revalidation, requires approval, or is already selected by the client's own Payment Process Request. If your controller uses an installment-level hold instead of a pay-group exclusion, release the hold (PATCH .../invoiceInstallments with HoldFlag: false) immediately before this call, in the same step, never after.
Receivables
On Invoice.Opened:
1. Find or create the customer
Create the party first if it doesn't exist:
curl -X POST "https://your-pod.fa.us2.oraclecloud.com/crmRestApi/resources/11.13.18.05/hubOrganizations" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{ "OrganizationName": "Northwind Health", "EmailAddress": "[email protected]" }'Turning that party into a billable customer account, site, and bill-to use is Oracle's synchronous SOAP foundationParties/CustomerAccountService. For a sync that already has to batch, the better fit for volume is Customer Import FBDI (CustomerImportTemplate.xlsm, run through "Import Trading Community Data in Bulk"), which creates the party, account, site, and site use together.
2. Create the AR invoice
curl -X POST ".../receivablesInvoices" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"BusinessUnit": "US Business Unit",
"TransactionSource": "Wingspan",
"TransactionType": "Invoice",
"TransactionDate": "2026-10-07",
"InvoiceCurrencyCode": "USD",
"BillToCustomerNumber": "NORTHWIND-001",
"BillToSite": "MAIN",
"PaymentTerms": "Net 30"
}'BillToCustomerNumber and BillToSite are the attribute names (not BillToCustomerAccountNumber/BillToSiteUseId). TransactionSource must be a manual-type source your Receivables admin configures. For the payment link Wingspan generates, write it to SpecialInstructions, Comments, InternalNotes, StructuredPaymentReference, or a Descriptive Flexfield, whichever your controller prefers.
3. Record the payment
Once Wingspan collects, post a standard receipt with a remittance reference naming the transaction:
curl -X POST ".../standardReceipts" \
-u "$FUSION_USER:$FUSION_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"CustomerAccountNumber": "NORTHWIND-001",
"CustomerSite": "MAIN",
"Amount": 945.00,
"CurrencyCode": "USD",
"ReceiptDate": "2026-10-08",
"remittanceReferences": [
{ "ReceiptMatchBy": "Invoice", "ReferenceNumber": "<Fusion invoice number>", "ReferenceAmount": 945.00 }
]
}'There's no REST apply action. Oracle's own asynchronous "Apply Receipts Using AutoMatch" process applies the receipt against the transaction named in the remittance reference, or leaves it unidentified if it can't match.
Idempotency and retries
Fusion REST has no idempotency-key mechanism. InvoiceNumber is unique per supplier (AP) and per transaction source (AR), so a naive retry after a timeout either creates a duplicate under a different number or fails with a duplicate-number error under the same one. Before any create, check your sync log, then look up the record in Fusion by the number you'd use, and create only on a miss.
Subscribe to Wingspan events
curl -X POST "https://api.wingspan.app/v3/platform/webhooks" \
-H "Authorization: Bearer $WINGSPAN_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://sync.example.com/webhooks/wingspan",
"subscribedEvents": ["Payable.Paid", "Payable.Returned", "Invoice.Opened", "Invoice.Cancelled", "InvoicePayment.Completed"],
"scope": { "type": "Account", "id": "<accountId>", "shouldIncludeDescendants": true },
"description": "Oracle Fusion Cloud sync"
}'- Store the
secretfrom the response. Wingspan returns it once. - Check
Wingspan-Signatureon every push. See Verify signatures. - Answer with a
2xxquickly and do the Fusion work after. - Read the event log every 15 minutes from a saved cursor, and run the search-row sweep on the same schedule. See Recover missed events.
Pitfalls
InvoiceSource, notSource. AndBusinessUnitis required on create.LineAmount, notAmount, on invoice lines.- A new supplier defaults to
Prospective. SetBusinessRelationship: Spend Authorizedexplicitly, or invoicing fails with no obvious link back to this field. - A supplier needs a site before it can be invoiced.
- Bank accounts and payment attributes live on separate resources from
Suppliers. A singleBATCHcan't span Procurement and Financials resource families. payablesPaymentsfails without its disbursement setup. The bank account, payment method, payment process profile, and payment document all have to exist before the first write.- A held or already-selected installment rejects the payment. Release an installment-level hold immediately before the write, never after; an invoice-level hold also drops the invoice out of any read filter scoped to
ValidationStatus=Validated. - Business Events are off by default (the "AP: Enable Business Events" profile option), and even on, they're only raised for invoices created through the UI or REST, never through a bulk FBDI import.
receivablesInvoicesfield names:BillToCustomerNumber/BillToSite, notBillToCustomerAccountNumber/BillToSiteUseId.InvoiceStatuson a Receivables invoice is a completion flag (Complete/Incomplete/Frozen), not a paid/open flag. ReadInvoiceBalanceAmountfor that.- No REST apply for a standard receipt. Post it with a remittance reference and let AutoMatch apply it, or use the SOAP
StandardReceiptServiceif you need synchronous apply. - No idempotency key on Fusion REST. Look up by number before every create.
- GL dimensions use the chart of accounts you already have. It's the Descriptive Flexfield, for anything that isn't a GL segment, that needs new setup.
- Fusion can add tax during validation. Confirm with your controller how tax lines reconcile against the amount your sync originally sent.
- No published rate limit. Keep concurrency to a few requests at a time and back off on
429/503.
Before you go live
- Agree the mapping with your controller: business units, the chart-of-accounts mapping, the pay-group or payment-method exclusion for AP, who owns 1099 filing and withholding, and the cutover date.
- Set up the disbursement bank account, payment method, payment process profile, and payment document for AP; the manual transaction source for AR.
- Confirm the integration user's job roles and Business Unit data access.
- Run one payable and one invoice end to end against a Fusion test environment, including a validation failure and a payment rejection, before pointing the sync at production.
- Turn on the webhook subscription with the event log starting at its head, then backfill anything open at cutover.
Related pages
Updated 9 days ago