async create(data, options) {
        if (!options) {
            options = {};
        }

        if (!options.batch_id) {
            // We'll use this to link related events
            options.batch_id = ObjectId().toHexString();
        }

        const {labels, stripeCustomer, offerId, attribution} = data;

        if (labels) {
            labels.forEach((label, index) => {
                if (typeof label === 'string') {
                    labels[index] = {name: label};
                }
            });
        }

        const memberData = _.pick(data, ['email', 'name', 'note', 'subscribed', 'geolocation', 'created_at', 'products', 'newsletters', 'email_disabled']);

        // Generate a random transient_id
        memberData.transient_id = await this._generateTransientId();

        // Throw error if email is invalid using latest validator
        if (!validator.isEmail(memberData.email, {legacy: false})) {
            throw new errors.ValidationError({
                message: tpl(messages.invalidEmail),
                property: 'email'
            });
        }

        memberData.email_disabled = !!memberData.email_disabled;

        if (memberData.products && memberData.products.length > 1) {
            throw new errors.BadRequestError({message: tpl(messages.moreThanOneProduct)});
        }

        if (memberData.products) {
            for (const productData of memberData.products) {
                const product = await this._productRepository.get(productData);
                if (product.get('active') !== true) {
                    throw new errors.BadRequestError({message: tpl(messages.tierArchived)});
                }
            }
        }

        const memberStatusData = {
            status: 'free'
        };

        if (memberData.products && memberData.products.length === 1) {
            memberStatusData.status = 'comped';
        }

        // Subscribe members to default newsletters
        if (memberData.subscribed !== false && !memberData.newsletters) {
            const browseOptions = _.pick(options, 'transacting');
            memberData.newsletters = await this.getSubscribeOnSignupNewsletters(browseOptions);
        }

        const withRelated = options.withRelated ? options.withRelated : [];
        if (!withRelated.includes('labels')) {
            withRelated.push('labels');
        }
        if (!withRelated.includes('newsletters')) {
            withRelated.push('newsletters');
        }

        const member = await this._Member.add({
            ...memberData,
            ...memberStatusData,
            labels
        }, {...options, withRelated});

        for (const product of member.related('products').models) {
            await this._MemberProductEvent.add({
                member_id: member.id,
                product_id: product.id,
                action: 'added'
            }, options);
        }

        const context = options && options.context || {};
        const source = this._resolveContextSource(context);

        const eventData = _.pick(data, ['created_at']);

        if (!eventData.created_at) {
            eventData.created_at = member.get('created_at');
        }

        await this._MemberStatusEvent.add({
            member_id: member.id,
            from_status: null,
            to_status: member.get('status'),
            ...eventData
        }, options);

        const newsletters = member.related('newsletters').models;

        for (const newsletter of newsletters) {
            await this._MemberSubscribeEvent.add({
                member_id: member.id,
                newsletter_id: newsletter.id,
                subscribed: true,
                source,
                ...eventData
            }, options);
        }

        if (newsletters && newsletters.length > 0) {
            this.dispatchEvent(MemberSubscribeEvent.create({
                memberId: member.id,
                source: source
            }, eventData.created_at), options);
        }

        // For paid members created via stripe checkout webhook event, link subscription
        if (stripeCustomer) {
            await this.upsertCustomer({
                member_id: member.id,
                customer_id: stripeCustomer.id,
                name: stripeCustomer.name,
                email: stripeCustomer.email
            });

            for (const subscription of stripeCustomer.subscriptions.data) {
                try {
                    await this.linkSubscription({
                        id: member.id,
                        subscription,
                        offerId,
                        attribution
                    }, {batch_id: options.batch_id});
                } catch (err) {
                    if (err.code !== 'ER_DUP_ENTRY' && err.code !== 'SQLITE_CONSTRAINT') {
                        throw err;
                    }
                    throw new errors.ConflictError({
                        err
                    });
                }
            }
        }
        this.dispatchEvent(MemberCreatedEvent.create({
            memberId: member.id,
            batchId: options.batch_id,
            attribution: data.attribution,
            source
        }, eventData.created_at), options);

        return member;
    }
Create a member
@param {Object} data
@param {string} data.email
@param {string} [data.name]
@param {string} [data.note]
@param {(string|Object)[]} [data.labels]
@param {boolean} [data.subscribed] (deprecated)
@param {string} [data.geolocation]
@param {Date} [data.created_at]
@param {Object[]} [data.products]
@param {Object[]} [data.newsletters]
@param {Object} [data.stripeCustomer]
@param {string} [data.offerId]
@param {import('@tryghost/member-attribution/lib/Attribution').AttributionResource} [data.attribution]
@param {boolean} [data.email_disabled]
@param {*} options
@returns