Public betaExpect changes and occasional bugs.About the beta

Developers · Public beta

Set your pre-order offer through the API

Create and edit private drafts, check what blocks publishing, then publish after reviewing the offer. This API uses the same creator and campaign rules as the website.

Download the JavaScript SDK · TypeScript declarations · OpenAPI reference

Authenticate as the creator

Use a current user access token issued by Earlybirdo’s Supabase project in the Authorization: Bearer header. Your app’s own Supabase tokens will not work. Sign in to Earlybirdo through your authorized Supabase client and complete two-factor verification when enrolled. Refresh the session through Supabase; the SDK calls getAccessToken for each request. Redemption keys and MCP tokens cannot manage offers through this API. Never use or distribute a service-role key.

The base URL is https://earlybirdo.com/api/v1. Same-origin web clients and server integrations are supported. Cross-origin browser calls need your own backend; no permissive CORS access is enabled.

import { createCreatorClient } from './creator-client.mjs';

// Reuse the Supabase client signed in to Earlybirdo, not your app's project.
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) throw new Error('Sign in to Earlybirdo first');

const offers = createCreatorClient({
  getAccessToken: async () => {
    const { data } = await supabase.auth.getSession();
    return data.session?.access_token ?? null;
  },
});

// Save this key with the operation. Reuse it after a timeout; use a new key for a new edit.
const draft = await offers.createOffer({
  title: 'Founding access to My App',
  tagline: 'One year of the Plus plan for founding customers',
  about: 'Includes one year of Plus features, starting when activated. Describe limits and support here.',
  category: 'apps',
  delivery_by: '2027-01-15',
  duration_days: 30,
  charge_timing: 'when_ready',
  refund_policy: 'anytime',
  perks: [{ name: 'Plus for one year', price: 49, spots: 250 }],
  milestones: [{ title: 'Access available', due_date: '2027-01-15' }],
}, { idempotencyKey: 'create-my-app-offer-v1' });

console.log(draft.offer.id, draft.publish_blockers);
// Upload an image to your own campaign-media folder with the Supabase Storage API.
await offers.updateOffer(draft.offer.id, {
  images: [user.id + '/my-app-cover.png'],
}, { idempotencyKey: 'set-my-app-cover-v1' });

// Show the final offer to the creator. Publish only after their explicit approval.
await offers.publishOffer(draft.offer.id, {
  confirm: true, idempotencyKey: 'publish-my-app-offer-v1',
});

Fields and retries

Listing includes campaigns you own and campaigns where you accepted a collaboration invitation. Collaborators can read and edit drafts without a paid plan; only the owner can publish, using their plan or campaign credits. Manage invitations and unique partner share links in the campaign dashboard.

Write prices and shipping in US dollars, with at most two decimal places. Returned database records use price_cents and shipping_cents. Omitted fields are preserved; supplied perks and milestones replace their entire lists. Every write needs an Idempotency-Key. Reusing a key with a different request returns 409; a retry of the same request returns its original result. Use GET to retrieve the latest state.

Images are paths uploaded under the creator’s user ID in campaign-media. Set place for local offers, redeem_until for in-person windows, and shipping details for physical perks. Published offers cannot be edited through this draft API.

Before selling app access

Define the paid features, usage limits, duration and support included. Verify activation and revocation in your app before publishing. Creating an offer does not provision features in another app. Identity verification, payment setup and campaign credits still apply.

Connect the purchase to app access →