Create a Private Offer via API

Overview

Create an Oracle Cloud Marketplace private offer programmatically with the Fours CreateOffer endpoint. Fours creates the offer in OCI, attaches the contract document, and sends it to the buyer — the same flow the console runs, driven from your own system.

The call is asynchronous. Fours validates the request, persists a DRAFT offer, returns it immediately, and then works with OCI in the background. The offer’s real status arrives through the hourly marketplace sync; poll the offer to follow it.

Prerequisites

  • An Oracle Marketplace integration connected at the organization level.
  • The product synced into Fours from your OCI listing — Fours resolves the listing OCID from the product’s external ID, so a product created by hand will not work. See List a Product.
  • The buyer’s tenancy OCID, or an existing Fours buyer record whose partner is ORACLE.
  • A contract document (EULA) reachable over https, or already uploaded to Fours.
  • An access token — see OAuth App.

Endpoint

POST https://api.suger.cloud/org/{orgId}/offer
Operation IDCreateOffer
AuthAuthorization: Bearer <access_token>
BodyA WorkloadOffer object
Success200 with the created WorkloadOffer

Request fields

Top level

FieldRequiredNotes
partner✅ORACLE
service✅MARKETPLACE
offerType✅PRIVATE. Oracle supports no other type — CPPO_OUT and channel offers are rejected.
productID✅Fours product ID. Must be an Oracle-synced product carrying the listing OCID.
name✅Becomes the offer’s displayName in OCI. Oracle rejects an empty name.
buyerID⬜A Fours buyer to link. Required only if you omit info.oracleOffer.buyerTenancyOCID; the buyer must belong to partner ORACLE.

info

FieldRequiredNotes
info.eulaUrl✅The contract document. Either an https URL that Fours fetches server-side, or the key of a file you uploaded to Fours. Plain http is rejected. Must resolve to a PDF of at most 1MB (Oracle’s per-attachment limit).
info.additionalEulaUrls⬜Further contract documents, same format and limits as info.eulaUrl. Each becomes its own attachment on the OCI offer (unlike AWS, where additional EULAs are merged into one document).
info.currency⬜ISO-4217 code. Defaults to USD.
info.commits⬜The offer’s line items. Their total becomes the offer’s totalAmount — see Pricing below.

info.oracleOffer

Oracle-specific fields, an OracleMarketplaceOffer object.

FieldRequiredNotes
sellerPrimaryContact✅Must include email. Oracle fails the send with SELLER_INFORMATION_IS_NULL without it.
buyerPrimaryContact✅Must include email. Oracle rejects the send without a buyer contact.
buyerTenancyOCID✅*The buyer’s OCI tenancy OCID. *Required unless you set buyerID to a linked Oracle buyer; when both are present, this field wins.
buyerCompanyName⬜Buyer’s company name.
description⬜Offer description shown in OCI.
duration⬜ISO-8601 contract length (P1Y, P6M, P30D, …), measured from timeStartDate — or from the creation time when billing starts on acceptance. Defaults to P1Y (one year). Oracle accepts only day-based durations, so Fours converts the value to days before sending: P1Y goes out as P365D (or P366D across a February 29). Oracle’s maximum total contract length is 375 days, so P2Y and P3Y are rejected at send time.
timeEndDate⬜An explicit end date, used instead of duration when both are set. Fours converts it to a day count from the start, rounding partial days up. Must be after timeStartDate, or in the future when billing starts on acceptance.
timeStartDate⬜When billing starts. Omit it to start billing when the buyer accepts — the default.
timeAcceptBy⬜Deadline for the buyer to accept. Defaults to 30 days out, or to the day before timeStartDate if that is sooner. Must be before timeStartDate — Oracle rejects the send otherwise.

Contact objects take firstName, lastName, and email.

Pricing

Oracle offers are sent to OCI with a single ONE_TIME billing cycle and one total amount. Fours computes that total from info.commits:

totalAmount = round( Σ (commit.rate × commit.quantity) )
  • A commit with no quantity counts as 1.
  • The sum is rounded to the nearest whole unit of currency, never truncated.
  • Omit info.commits entirely and the offer is created with a total of 0 — which Oracle rejects at send time, because its minimum contract value is 10,000 USD.

Example

Always include info.commits. Oracle requires a minimum contract value of 10,000 USD, so an offer whose commits sum to less than that — including an offer with no info.commits at all, which Fours sends as a $0 total — is rejected by Oracle at send time and ends up as CREATE_FAILED. Usage reported on the resulting entitlement is billed in addition to this contract value, not instead of it; see Usage Metering.

curl -L -X POST 'https://api.suger.cloud/org/YOUR_ORG_ID/offer' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "partner": "ORACLE",
    "service": "MARKETPLACE",
    "offerType": "PRIVATE",
    "productID": "KVvfb0Vhv",
    "name": "Acme Corp - Annual Contract 2026",
    "info": {
      "currency": "USD",
      "eulaUrl": "https://acme.example.com/legal/eula-2026.pdf",
      "additionalEulaUrls": [
        "https://acme.example.com/legal/annex-a-2026.pdf"
      ],
      "commits": [
        { "name": "Platform subscription", "rate": 50000, "quantity": 1 }
      ],
      "oracleOffer": {
        "description": "Annual platform subscription for Acme Corp.",
        "duration": "P1Y",
        "buyerTenancyOCID": "ocid1.tenancy.oc1..aaaaaaaaexamplebuyertenancy",
        "buyerCompanyName": "Acme Corp",
        "buyerPrimaryContact": {
          "firstName": "Ada",
          "lastName": "Lovelace",
          "email": "[email protected]"
        },
        "sellerPrimaryContact": {
          "firstName": "Grace",
          "lastName": "Hopper",
          "email": "[email protected]"
        }
      }
    }
  }'

The response is the persisted offer. Note status — it is the Fours record, not yet the OCI state:

{
  "id": "FIwCbefqu",
  "organizationID": "YOUR_ORG_ID",
  "partner": "ORACLE",
  "service": "MARKETPLACE",
  "offerType": "PRIVATE",
  "productID": "KVvfb0Vhv",
  "buyerID": "gHYis9RKU",
  "name": "Acme Corp - Annual Contract 2026",
  "status": "DRAFT",
  "info": {
    "currency": "USD",
    "visibility": "PRIVATE",
    "deliveryMethod": "PRIVATE"
  }
}

Keep the returned id. It is the Fours offer ID used for every follow-up call, and it doubles as the idempotency token for the OCI create — a retried submission will not produce a duplicate buyer-visible offer.

Track the offer

curl -L -X GET 'https://api.suger.cloud/org/YOUR_ORG_ID/offer/FIwCbefqu' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

Immediately after the 200, Fours moves the offer to PENDING_CREATE while it creates the offer in OCI, attaches the contract, and sends it — about five minutes. Once OCI has the offer, info.oracleOffer.offerID holds the private-offer OCID and info.oracleOffer.offerStatus holds Oracle’s raw status. Fours maps that raw status onto its own:

Oracle offerStatusFours status
DRAFTDRAFT
PENDING_MARKETPLACEPENDING_MARKETPLACE_APPROVAL
PENDING_BUYERPENDING_ACCEPTANCE
ACCEPTEDACCEPTED
ACTIVEACTIVE
ENDED, EXPIREDEXPIRED
FAILED_SEND, FAILED_ACCEPTCREATE_FAILED

When Oracle rejects the send, info.oracleOffer.lifecycleDetails carries Oracle’s reason — for example DURATION_IS_INVALID or TIME_ACCEPT_BY_IS_INVALID — and the offer’s metaInfo.errorMessages records it as … send rejected (FAILED_SEND: <reason>).

The Fours-side lifecycle, from the synchronous response through the hourly sync:

As soon as the offer is ACCEPTED, Fours derives an entitlement for the buyer — ACTIVE straight away when the offer has no timeStartDate (billing starts on acceptance); otherwise PENDING_START until the offer’s start date, ACTIVE from then on. Buyers are deduped by tenancy OCID, so repeat deals with the same customer attach to the same buyer record.

Withdraw an offer

curl -L -X POST 'https://api.suger.cloud/org/YOUR_ORG_ID/offer/FIwCbefqu/cancel' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

Oracle allows withdrawing any offer the buyer has not yet accepted, so this is valid while the offer is PENDING_ACCEPTANCE or PENDING_MARKETPLACE_APPROVAL. Once accepted, it can no longer be withdrawn.

Validation errors

These are returned as 400 before anything is created in OCI, so a rejected request never leaves an orphaned draft in your marketplace account.

MessageFix
invalid offer type ... to create private offer in Oracle MarketplaceSet offerType to PRIVATE.
offer name is requiredSet name.
info.eulaUrl is requiredProvide a contract document.
info.eulaUrl ... must be an https URLUse https, not http.
info.oracleOffer.sellerPrimaryContact (with email) is requiredAdd the seller contact with an email.
info.oracleOffer.buyerPrimaryContact (with email) is requiredAdd the buyer contact with an email.
buyer tenancy OCID is required ...Set info.oracleOffer.buyerTenancyOCID, or link an Oracle buyer via buyerID.
info.oracleOffer.timeAcceptBy (...) must be before timeStartDate (...)Move timeAcceptBy before timeStartDate, or omit it to take the default.
info.oracleOffer.timeEndDate (...) must be after timeStartDate (...)Move timeEndDate after the start, or send a duration instead.
info.oracleOffer.timeEndDate (...) must be in the future when billing starts on acceptanceUse a future end date, or send a duration instead.
info.oracleOffer.duration "..." is not a valid ISO-8601 period ...Send a period such as P1Y, P6M or P30D.
info.oracleOffer.duration "..." must be a non-zero periodSend a positive period, or omit duration for the one-year default.

Two further checks need OCI context and therefore surface after the API has returned, as a CREATE_FAILED offer rather than a 400:

  • The product must resolve to an Oracle listing OCID.
  • A linked buyerID must belong to partner ORACLE; a buyer imported from another marketplace is refused.

Spotted something wrong or out of date on this page? Tell us and we'll correct it.